Arquillian tutorial

Arquillian is a platform that simplifies integration testing for Java middleware. It deals with all the plumbing of container management, deployment, and framework initialization so you can focus on the task of writing your tests—real tests. Arquillian minimizes the burden on you—the developer—by covering aspects surrounding test execution; some of these aspects are as follows:

  • Managing the life cycle of the container (start/stop)
  • Bundling the test class with the dependent classes and resources into a deployable archive
  • Enhancing the test class (for example, resolving @Inject, @EJB, and @Resource injections)
  • Deploying the archive to test applications (deploy/undeploy), and capturing results and failures

Enough with introductions, let's get our hands dirty with a real example!

Do you need a maven archetype to get started quickly with Arquillian ? then build your project with the following one, which will create a project named javaee7arquillian with a Demo application in it:

mvn --batch-mode archetype:generate -DarchetypeGroupId=org.javaee-samples -DarchetypeArtifactId=javaee7-arquillian-archetype -DgroupId=com.mastertheboss -DartifactId=javaee7arquillian

The following is an Arquillian Test Class which is going to test a full Java EE project:

package com.mastertheboss.test;

import java.util.List;
import java.util.UUID;

import javax.inject.Inject;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;

import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.mastertheboss.model.SimpleProperty;
import com.mastertheboss.producer.Producer;
import com.mastertheboss.ejb.ServiceBean;
import com.mastertheboss.repository.RepositoryManager;

@RunWith(Arquillian.class)
public class ServiceTest {
	@Deployment
	public static Archive<?> createTestArchive() {
		return ShrinkWrap.create(WebArchive.class, "test.war").addPackage(ServiceBean.class.getPackage())
				.addPackage(Producer.class.getPackage()).addPackage(SimpleProperty.class.getPackage())
				.addPackage(RepositoryManager.class.getPackage()).addAsResource("META-INF/persistence.xml")
				.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");

	}

	@Inject
	ServiceBean ejb;

	@Inject
	RepositoryManager repo;

	@Test
	public void testRegister() throws Exception {
		String key = UUID.randomUUID().toString();
		String value = UUID.randomUUID().toString();
		SimpleProperty p = new SimpleProperty();
		p.setKey(key);
		p.setValue(value);
		ejb.put(p);

		List<SimpleProperty> list = repo.queryCache();
		assert (list.size() > 0);

		assert (list.get(0).getKey().equals(key));

	}

}

This class is part of a Project which is available onn GitHub at: https://github.com/fmarchioni/mastertheboss/tree/master/javaee/javaee7arquillian . The purpose of this example is to insert a key/value pair using the ServiceBean EJB and then use the RepositoryManager class to verify that data has been actually inserted.
The first thing that you should have noticed is the following annotation that tells JUnit to use Arquillian as the test controller:

@RunWith(Arquillian.class)
public class ArquillianTest {
}


Arquillian then looks for a static method with the @Deployment annotation; it creates a micro deployment, including all the resources, just as you would when packaging your applications with your favorite tool:

The fluent API provided by the ShrinkWrap project (http://www.jboss.org/shrinkwrap) makes this technique possible using the create method, which accepts the type of deployment unit (WebArchive) as the argument thedeployment name (in our case, we will name it test-demo.war) and all the resources are included in this archive. In our case, instead of including all the single classes, we are using the addPackageutility method that adds all the classes that are contained in a class package.

Building the Arquillian test

Although Arquillian does not depend on a specific build tool, it is commonly used with Maven; it offers dependency management and thus simplifies the task of including the Arquillian libraries in the application since they are distributed in the Central Maven repository.

The first thing that is necessary to include in order to run an Arquillian test is the JUnit dependency that is required to run our unit tests:

<dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <scope>test</scope>
</dependency>

Next, if you want to test enterprise features such as EJB and the Java Transaction API (JTA), you need to include the  org.jboss.arquillian.junit dependency as well:

<dependency>
 <groupId>org.jboss.arquillian.junit</groupId>
 <artifactId>arquillian-junit-container</artifactId>
 <scope>test</scope>
</dependency>

After that, since our Arquillian test uses a protocol to communicate with the server application, we will need to add the org.jboss.arquillian.protocol dependency (named so as it's compatible with Servlet 2.5/3.0 specifications):

<dependency>
 <groupId>org.jboss.arquillian.protocol</groupId>
 <artifactId>arquillian-protocol-servlet</artifactId>
 <scope>test</scope>
</dependency>

After getting done with the dependencies, we will now include two profiles into our configuration. A profile can basically be used to create different target environments for our goals; in our case, we will create two profiles:
The first profile is named arq-jbossas-managed; it will start a new JBoss AS instance and execute the test, shutting it down when done:

<profile>
   <!-- Run with: mvn clean test -Parq-wildfly-managed -->
   <id>arq-wildfly-managed</id>
   <dependencies>
      <dependency>
         <groupId>org.wildfly.arquillian</groupId>
         <artifactId>wildfly-arquillian-container-managed</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
</profile>

The second profile is named arq-jbossas-remote; it will perform testing against a remote JBoss AS instance:

<profile>
   <!-- Run with: mvn clean test -Parq-wildfly-remote -->
   <id>arq-wildfly-remote</id>
   <dependencies>
      <dependency>
         <groupId>org.wildfly.arquillian</groupId>
         <artifactId>wildfly-arquillian-container-remote</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
</profile>

Running Arquillian Test with a managed container

Arquillian needs to know where WildFly is installed so that it can manage the lifecycle of the container using the startup script. You can configure the JBOSS HOME application into the arquillian.xml file shown as follows:

 
<arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
   <defaultProtocol type="Servlet 3.0" />
   <container qualifier="jboss" default="true">
      <configuration>
         <property name="jbossHome">/home/francesco/jboss/wildfly-10.1.0.Final</property>
      </configuration>
   </container>
</arquillian>

Run the test from a terminal windows (or from within your IDE which supports Maven) using:

mvn clean test -Parq-jbossas-managed

Running Arquillian Test with a remote container

You can run the test against a remote JBoss AS installation which by default should be running on localhost and 9999 as management port. You can however override these values by adding to arquillian.xml the following parameters:

<arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
   <defaultProtocol type="Servlet 3.0" />
   <container qualifier="jboss" default="true">
      <configuration>
         <property name="managementAddress">myhost</property>
         <property name="managementPort">9990</property>
      </configuration>
   </container>
</arquillian>

In order to run it from a terminal window execute:

mvn clean test -Parq-jbossas-remote

Troubleshooting common Arquillian issues:

My Arquillian tests aren't being executed!

It's likely that you are using the surefire-maven-plugin. This plugin does not recognize tests that ends with *IT. You should change it's name to *Test or use other technique.

I get the following error when launching the test: Caused by: java.lang.IllegalArgumentException: DeployableContainer must be specified

It's likely that you have no active profile in your pom.xml. Activate the default Arquillian profile as in the following example:

<profile>
   <id>arq-wildfly-managed</id>
   <activation>
      <activeByDefault>true</activeByDefault>
   </activation>
   <dependencies>
      <dependency>
         <groupId>org.wildfly.arquillian</groupId>
         <artifactId>wildfly-arquillian-container-managed</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
</profile>

As an alternative, launch Maven selecting the profile you're interested in:

mvn clean test -Parq-jbossas-remote

Practical Java EE 7 development on WildFly

This tutorial includes resources from the Practical Java EE 7 development on WildFly If you liked it, consider purchasing a copy of it from Packt Publishing Site

Follow us on Twitter