How To Use Arquillian(update)
Arquillian is an integration and functional testing framework for JavaEE and i always connect it with the phrase Write real world tests. But what does it mean exactly? What is a real world test?
For me real world test means that the execution environment is the same (or as near as possible) to my production environment and exactly that is what Arquillian provides.
- You do not need mock frameworks anymore (e.g. Mockito, EasyMock, JMockit)
- You do not have to care about for example the integration of a bean because now you can simply inject it to your test
- With Shrinkwrap (bundled into Arquillian) you are able to build an artifact with all your required dependencies so that those are explicit and makes tests more readable/understandable
- In times of Microservices and Docker you can also use Arquillian Cube for managed Docker containers. (If you wonder about the name read here)
The only drawback i found so far is that it does not work with standard JUnit Parameterized but this is more related to JUnit since it does not allow more than one runner per test class. Usually this restriction is overcome by implementing the functionality as JUnit Rule and fortunately there are two already:
- http://www.poolik.com/2014/02/how-to-run-parameterized-junit-arquillian-tests
- https://gist.github.com/aslakknutsen/1358803
I also had some discussions about performance of Arquillian tests which are by nature a little bit slower than plain JUnit tests. The standard argument is slow startup time of the containers. But for one thing almost every container (incl. application servers) starts up within seconds and usually performance on a Jenkins is of secondary importance. During development it is recommended to use a remote container so that start up time does not apply anymore.
One important question for me is when to use a framework or tool and when not to use it. From my point of view Arquillian can be used in almost any case except for DAO tests. Sure it works and does not look bad but for me it feels a little bit heavy weight. Especially in comparison with Rulz of Adam Bien it looks a little bit strange.
Further information about Arquillian can be found on the Arquillian website.
Containers
Since i always forget some of the differences between different container types the following diagram serves as a helper.
Info:
- Same/Separate JVM: refers to the test runner.
- Isolated/Not Isolated Container: due to the JVM binding (same/separate) a container can have some unexpected effects in not isolated containers as you can read here.
- Lifecycle Managed: Means that an container is started as well as shutdown.
The specific container provider can be divided further into the following three groups:
- a fully compliant Java EE application server (e.g. Glassfish, Wildfly)
- a servlet container (e.g. Jetty, Tomcat)
- a standalone bean container (e.g. Weld SE, Spring)
Usage
In order to run an Arquillian test you need to do the following three steps:
- Provide an arquillian.xml which declares and configures containers (e.g. arquillian-wildfly-managed)
- Provide arquillian container dependency
1 <plugin>
2 <artifactId>maven-surefire-plugin</artifactId>
3 <version>2.19</version>
4 <configuration>
5 <systemPropertyVariables>
6 <!-- reference to arquillian.xml container -->
7 <arquillian.launch>arquillian-wildfly-managed</arquillian.launch>
8 </systemPropertyVariables>
9 </configuration>
10 </plugin>
- Provide arquillian test
1 @Stateless
2 public class ServiceFacade {
3 public String getHello() {return "hello";}
4 public String getPrint() {return "print";}
5 }
1 @RunWith(Arquillian.class)
2 public class ServiceFacadeHelloTest {
3
4 @Inject ServiceFacade serviceFacade;
5
6 @Deployment
7 public static WebArchive create() {
8
9 //testHello and testPrint are using assertj
10 //therefore the container needs to know it
11 File[] libs = Maven.resolver()
12 .loadPomFromFile("pom.xml")
13 .resolve("org.assertj:assertj-core")
14 .withTransitivity().as(File.class);
15
16 return ShrinkWrap.create(WebArchive.class, "mytest.war")
17 .addAsLibraries(libs)
18 .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")
19 .addClass(ServiceFacade.class);
20 }
21
22 @Test
23 public void testHello() {
24 assertThat(serviceFacade.getHello()).isEqualTo("hello");
25 }
26
27 @Test
28 public void testPrint() {
29 assertThat(serviceFacade.getPrint()).isEqualTo("print");
30 }
31 }
The snippet above is testing a simple session bean with AssertJ via Arquillian. The important part for using Arquillian is:
- Declare Arquillian JUnit runner with @RunWith(Arquillian.class)
- Provide an archive with a static method marked with @Deployment which is then deployed to the container. In this case ShrinkWrap is used to create a web archive which contains the AssertJ library, an empty beans.xml and the ServiceFacade.
Note: JBoss Forge provides already the arquillian-addon.
The following repository contains a working example for three wildfly arquillian containers: embedded, managed and remote.