Mitch Pronschinske is a Senior Content Analyst at DZone. That means he writes and searches for the finest developer content in the land so that you don't have to. He often eats peanut butter and bananas, likes to make his own ringtones, enjoys card and board games, and is married to an underwear model. Mitch is a DZone Zone Leader and has posted 2573 posts at DZone. You can read more from them at their website. View Full User Profile

Arquillian in Action; New Features Coming Soon

03.15.2010
| 10217 views |
  • submit to reddit
Java developers finally have a chance to get their hands on a powerful open source JEE testing tool from JBoss.  Arquillian is an extension for testing frameworks such as JUnit and TestNG that can be used to validate the behavior of managed beans, enterprise beans, or POJOs relying on enterprise services.  The 1.0.0 alpha 1 version of Arquillian was just released and JBoss says they are ready to put it to work on Seam 3 testing even at this early stage.  Arquillian is intended to make integration testing just as easy as unit testing.  Here we'll provide some examples of Arquillian in action and review all the features that will be added in the upcoming releases.  There is also an introductory article on Arquillian that gives a good overview of what the technology can do.

Developers can build and execute Arquillian tests much like a regular unit test, and the testing environments can be easily swapped or used in sequence.  With the help of the ShrinkWrap API, groups of tests are packaged as Java EE archives, which enables fine-grained control over the resources to be tested.  Test archives can then be deployed and executed inside a pluggable Java EE container (remote or embedded) or a bootstrapped CDI (Contexts and Dependency Injection {JSR 299}) environment.  Finally, an RPC-style communication between the environment and the test runner negotiates which tests are executed and relays back the results.  Let's take a look at two examples of Arquillian in action over at JBoss:

JMS Module Testing for Seam 3

Arquillian was used in the testing of Seam 3, in this case, to demonstrate that the injection of JMS resources and CDI event forwarding to JMS works correctly.  Arquillian is all about testing in the container so you can test against the managed resources.  This test is set up using Arquillian to run on the JBoss AS jboss-remote-60 profile 6.0.  JUnit 4 is the testing framework and JBoss Messaging is the JMS provider.  JBoss Messaging enables deployment descriptors for destinations to be bundled with deployments, meaning you can set up a test case for JMS resource injection entirely within Arquillian.  This example will also test the deployment of JBoss Messaging destinations through Arquillian.

JBoss first sets up the ShrinkWrap deployment archive to include the JMA portable extension, required classes, and the topic destination's configuration in order to test simple destination injection:
@RunWith(Arquillian.class)
public class JmsResourceInjectionTest {
@Deployment
public static Archive<?> createTestDeployment()
{
return Archives.create("test.jar", JavaArchive.class)
.addPackages(false, Seam3JmsExtension.class.getPackage(), SimpleInjectionTest.class.getPackage())
.addManifestResource(new ByteArrayAsset(new byte[0]), ArchivePaths.create("beans.xml"))
// Register the portable extension
.addServiceProvider(Extension.class, Seam3JmsExtension.class)
// Include JBoss Messaging topic configuration
.addManifestResource("topic_T-service.xml");
}
}
This is the topic destination config; topic_T-service.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<server>
<mbean xmbean-dd="xmdesc/Topic-xmbean.xml"
name="jboss.messaging.destination:service=Topic,name=T"
code="org.jboss.jms.server.destination.TopicService">
<attribute name="JNDIName">jms/T</attribute>
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends>jboss.messaging:service=PostOffice</depends>
</mbean>
</server>
Now let's test the injection of a topic directly into the test class:
@Inject Topic t;

@Test
public void simpleTopicInjection()
{
assertNotNull(t);
assertEquals("T", t.getTopicName());
}
A Topic producer method satisfies the injection point by taking the name of the field, capitalizing it, appending it to the string "/jms/", and then it finds the name (in this case /jms/T) in the JNDI InitialContext.

Arquillian is especially useful when it tests CDI events bridged to JMS.  The Seam 3 JMS module supports declaratively forwarding events over JMS.  Next, we'll look at a test case verifying that events are being forwarded to their proper destination.  First, a MessageConsumer and a simple test event are used to identify when messages are sent over JMS:
@Inject Connection c;
@Inject Session s;
@Inject @Events Topic t;
@Inject Seam3JmsExtension jmsExt;
@Inject Event<String> event;
For this test case you have to register the event type to be forwarded over JMS.  Then you create a MessageConsumer to consume events from the intended destination, and finally you send the event then check to see if it was received at the proper destination.
@Test(timeout=5000)
public void forwardEvent() throws Exception
{
String expected = "test";
jmsExt.register(String.class, t);
MessageConsumer mc = s.createConsumer(t);
c.start();
event.fire(expected);
Message m = mc.receive();
assertNotNull(m);
assertTrue(m instanceof ObjectMessage);
assertEquals(expected, ((ObjectMessage) m).getObject());
}
Learn more about CDI events on the Weld reference documentation page.

CDI JMX Portable Extension Test

In this example, German Escobar uses Arquillian to test a simple JMX Portable Extension he wrote that allows you to automatically register Managed Beans using annotations.  Here is an example of the extension being used:
@ApplicationScoped
@MBean("org.gescobar:type=VisitorCounter")
@Description("Counts the number of visits")
public class VisitorCounter {

@ManagedAttribute(readable=true,writable=true)
private int counter;

public void addVisitor() {
counter++;
}

@ManagedOperation(impact=Impact.ACTION)
public void resetCounter() {
counter = 0;
}

// getter and setters
}
Once the bean is instantiated, it is automatically registered as an MBean or an MBeanServer.  Escobar needed a way to test his extension on different containers so he used Arquillian with TestNG.

First, the TestNG and Arquillian dependencies are added to the pom.xml file:
  ...
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.10</version>
<classifier>jdk15</classifier>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-testng</artifactId>
<version>1.0.0.Alpha1</version>
<scope>test</scope>
</dependency>
...
Escobar created two profiles on his pom.xml for JBoss AS 6.0 M2 and Weld SE:
  <profiles>
<profile>
<id>jbossas-remote-60</id>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-jbossas-remote-60</artifactId>
<version>1.0.0.Alpha1</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>weld-embedded</id>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-weld-embedded</artifactId>
<version>1.0.0.Alpha1</version>
</dependency>
</dependencies>
</profile>
</profiles>
To test inside other containers, you simply create more profiles.  Then the final step is to write a test class.  Escobar had do two things to his regular TestNG class: Create a method annotated with @Deployment that returns a ShrinkWrap archive, and then the class must extend org.jboss.arquillian.testng.Arquillian.
public class TestAutoRegistration extends Arquillian { 

@Deployment
public static JavaArchive createDeployment() {

JavaArchive archive = Archives.create("test.jar", JavaArchive.class)
.addPackage(MBeanFactory.class.getPackage())
.addPackage(CDIMBeanFactory.class.getPackage())
.addPackage(MBeanServerLocator.class.getPackage())
.addClasses(CounterAutoRegisterWithName.class, CounterAutoRegisterNoName.class)
.addManifestResource("services/javax.enterprise.inject.spi.Extension")
.addManifestResource(
new ByteArrayAsset("<beans/>".getBytes()),
Paths.create("beans.xml"));

return archive;
}

@Inject
private CounterAutoRegisterWithName counterWithName;

@Inject
private CounterAutoRegisterNoName counterNoName;

@Test
public void shouldRegisterAnnotatedWithNameMBean() throws Exception {
Assert.assertNotNull(counterWithName);

// the bean is not created until the first call - maybe a bug in weld?
Assert.assertEquals(counterWithName.getCounter(), 0);

MBeanServer mBeanServer = MBeanServerLocator.instance().getmBeanServer();
ObjectName name = new ObjectName("org.gescobar:type=CounterAutoRegisterWithName");

// check we can add the counter
mBeanServer.setAttribute(name, new Attribute("counter", 1));
Assert.assertEquals(counterWithName.getCounter(), 1);

// check we can retrieve the counter
Integer result = (Integer) mBeanServer.getAttribute(name, "counter");
Assert.assertNotNull(result);

// check we can call method without arguments
mBeanServer.invoke(name, "resetCounter", null, null);
Assert.assertEquals(counterWithName.getCounter(), 0);

// check we can call method with arguments
mBeanServer.invoke(name, "resetCounter2", new Object[] { 5 }, new String[] { "java.lang.Integer" });
Assert.assertEquals(counterWithName.getCounter(), 5);
}

@Test
public void shouldRegisterAnnotatedWithNoNameMBean() throws Exception {
Assert.assertNotNull(counterNoName);

Assert.assertEquals(counterNoName.getCounter(), 0);

MBeanServer mBeanServer = MBeanServerLocator.instance().getmBeanServer();
Object result = mBeanServer.getAttribute(new ObjectName("org.gescobar.management.test:type=CounterAutoRegisterNoName"), "counter");

Assert.assertNotNull(result);
}
}
At this point, you run the test by calling the appropriate profiles, in this case Escobar called: mvn clean install -Pjbossas-remote-60 and mvn clean install -Pweld-embedded.  Now the extension is ready to be tested on real containers.  JBoss AS 6 must be running if you're using the remote profile because Arquillian doesn't start or stop the container automatically, but soon it will.

Coming Soon

These are some of the features and supports that you can expect as Arquillian progresses from alpha to beta, and finally to GA:

More Containers - JBoss plans to add Arquillian support for GlassFish v3 as a remote container (already supports it as an embedded container), Jetty, Tomcat, Resin, and Felix OSGi.  Spring is also welcome if they're interested.

Third Party Integrations - Support is planned for many other testing frameworks including JSFUnit, Selenium, and "Mock JSF Objects."

Convention over configuration
- To make micro deployments easier to create and to speed up test development, JBoss will add support for common conventions that can be reused in all your test cases.

Controlled Resources - To create an InitialContext, a container sometimes needs specific configuration parameters.  If the test case has to deal with this explicitly, it places the burden of container portability back on the test case author.  Arquillian will provide an extention point for adding Arquillian created/managed resources:
// auto creation of InitialContext based on running container, remote or local.
@ArquillianResource
private InitialContext context;

// auto creation of URL to a specific deployed Servlet, including http port/ip etc.
@ArquillianResource(MyServlet.class)
private URL myServletURL;

// the bundle context of a deployed osgi bundle
@ArquillianResource
private BundleContext context;

Embedded AS - JBoss Embedded AS support wasn't ready for the alpha 1 release, but it is definitely on its way.  Embedded AS allows you to bootstrap JBoss AS inside the same JVM when you run your test, which makes test debugging a breeze.

Build Tools - Right now Arquillian only comes with Maven support, but Ant and Gradle support are planned for upcoming releases.

Local Run Mode - A local run mode will be added to Arquillian so that you don't necessarily have to run the test case inside the container itself.  In local run mode, tests will control the deployment, but they won't be deployed as a part of it.  This will, for example, allow tests against JSF pages or RMI.

One Test Controlling Multiple Deployments - This will allow you to package other components as part of the same deployment.  For example, Arquillian will be able to test interactions between two web applications.

Method Argument Injection Support - Arquillian alpha 1 only supports field injection.  Alpha 2 will have an extended TestEnricher SPI to add support for method argument injection:
@Test
public void shouldWithdrawFromAccount(@EJB AccountManager manager) throws Exception
{
...
}

Test Method Interceptors - The test method interceptor SPI will add support for transactions:
@Test
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void shouldWithdrawFromAccount(@EJB AccountManager manager) throws Exception
{
...
}

Logo - This is probably the most important part of any project.  The project has an pretty sounding name, now they need a cool logo to go with it.  This too, is on its way.

JBoss will also replace the current core of the CDI TCK with Arquillian - most likely for the 1.1 version of the TCK.