JBoss.orgCommunity Documentation

Chapter 1. Introduction

1.1. Mission statement
1.2. Architecture overview
1.3. Integration testing in Java EE
1.3.1. Testing the real component
1.3.2. Finding a happy medium
1.3.3. Controlling the test classpath
1.4. Usage scenarios

We believe that integration testing should be no more complex than writing a basic unit test. We created Arquillian to realize that goal. One of the major complaints we heard about Seam 2 testing (i.e., SeamTest) was, not that it isn't possible, but that it isn't flexible and it's difficult to setup. We wanted to correct those shortcomings with Arquillian.

Testing needs vary greatly, which is why it's so vital that, with Arquillian (and ShrinkWrap), we have decomposed the problem into its essential elements. The result is a completely flexible and portable integration testing framework.

The mission of the Arquillian project is to provide a simple test harness that developers can use to produce a broad range of integration tests for their Java applications (most likely enterprise applications). A test case may be executed within the container, deployed alongside the code under test, or by coordinating with the container, acting as a client to the deployed code.

Arquillian defines two styles of container, remote and embedded. A remote container resides in a separate JVM from the test runner. Its lifecycle may be managed by Arquillian, or Arquillian may bind to a container that is already started. An embedded container resides in the same JVM and is mostly likely managed by Arquillian. Containers can be further classified by their capabilities. Examples include a fully compliant Java EE application server (e.g., GlassFish, JBoss AS, Embedded GlassFish), a Servlet container (e.g., Tomcat, Jetty) and a bean container (e.g., Weld SE). Arquillian ensures that the container used for testing is pluggable, so the developer is not locked into a proprietary testing environment.

Arquillian seeks to minimize the burden on the developer to carry out integration testing by handling all aspects of test execution, including:

To avoid introducing unnecessary complexity into the developer's build environment, Arquillian integrates transparently with familiar testing frameworks (e.g., JUnit 4, TestNG 5), allowing tests to be launched using existing IDE, Ant and Maven test plugins without any add-ons.

Arquillian makes integration testing a breeze.

Arquillian combines a unit testing framework (JUnit or TestNG), ShrinkWrap, and one or more supported target containers (Java EE container, servlet container, Java SE CDI environment, etc) to provide a simple, flexible and pluggable integration testing environment.

At the core, Arquillian provides a custom test runner for JUnit and TestNG that turns control of the test execution lifecycle from the unit testing framework to Arquillian. From there, Arquillian can delegate to service providers to setup the environment to execute the tests inside or against the container. An Arquillian test case looks just like a regular JUnit or TestNG test case with two declarative enhancements, which will be covered later.

Since Arquillian works by replacing the test runner, Arquillian tests can be executed using existing test IDE, Ant and Maven test plugins without any special configuration. Test results are reported just like you would expect. That's what we mean when we say using Arquillian is no more complicated than basic unit testing.

At this point, it's appropriate to pause and define the three aspects of an Arquillian test case. This terminology will help you better understand the explainations of how Arquillian works.

The test case is dispatched to the container's environment through coordination with ShrinkWrap, which is used to declaratively define a custom Java EE archive that encapsulates the test class and its dependent resources. Arquillian packages the ShrinkWrap-defined archive at runtime and deploys it to the target container. It then negotiates the execution of the test methods and captures the test results using remote communication with the server. Finally, Arquillian undeploys the test archive. We'll go into more detail about how Arquillian works in a later chapter.

So what is the target container? Some proprietary testing container that emulates the behavior of the technology (Java EE)? Nope, it's pluggable. It can be your actual target runtime, such as JBoss AS, GlassFish or Tomcat. It can even been an embedded container such as JBoss Embedded AS, GlassFish Embedded or Weld SE. All of this is made possible by a RPC-style (or local, if applicable) communication between the test runner and the environment, negotiating which tests are run, the execution, and communicating back the results. This means two things for the developer:

With that in mind, let's consider where we are today with integration testing in Java EE and why an easy solution is needed.

Integration testing is very important in Java EE. The reason is two-fold:

The first reason is inherent in enterprise applications. For the application to perform any sort of meaningful work, it has to pull the strings on other components, resources (e.g., a database) or systems (e.g., a web service). Having to write any sort of test that requires an enterprise resource (database connection, entity manager, transaction, injection, etc) is a non-starter because the developer has no idea what to even use. Clearly there is a need for a simple solution, and Arquillian fills that void.

Some might argue that, as of Java EE 5, the business logic performed by most Java EE components can now be tested outside of the container because they are POJOs. But let's not forget that in order to isolate the business logic in Java EE components from infrastructure services (transactions, security, etc), many of those services were pushed into declarative programming constructs. At some point you want to make sure that the infrastructure services are applied correctly and that the business logic functions properly within that context, justifying the second reason that integration testing is important in Java EE.

Let's move on and consider some typical usage scenarios for Arquillian.

With the strategy defined above, where the test case is executed in the container, you should get the sense of the freedom you have to test a broad range of situations that may have seemed unattainable when you only had the primitive unit testing environment. In fact, anything you can do in an application you can now do in your test class.

A fairly common scenario is testing an EJB session bean. As you are inside the container, you can simply do a JNDI lookup to get the EJB reference and your test becomes a client of the EJB. But having to use JNDI to get a reference to the EJB is inconvenient (at least to Java EE 5 developers that have become accustomed to annotation-based dependency injection). Arquillian allows you to use the @EJB annotation to inject the reference to an EJB session bean into your test class.

EJB session beans are one type of Java EE resource you may want to access. But that's just the beginning. You can access any resource available in a Java EE container, from a UserTransaction to a DataSource to a mail session. Any of these resources can be injected directly into your test class using the Java EE 5 @Resource annotation.

Resource injections are convenient, but they are so Java EE 5. In Java EE 6, when you think dependency injection, you think JSR-299: CDI. Your test class can access any bean in the ShrinkWrap-defined archive, provided the archive contains a beans.xml file to make it a bean archive. And you can inject bean instances directly into your class using the @Inject annotation, or you can inject an Instance reference to the bean, allowing you to create a bean instance when needed in the test. Of course, you can do anything else you can do with CDI within your test as well.

Another important scenario in integration testing is performing data access. If the ShrinkWrap-defined archive contains a persistence.xml descriptor, the persistence unit will be started when the archive is deployed and you can perform persistence operations. You can obtain a reference to an EntityManager by injecting it into your class with @PersistenceContext or from a CDI producer-field. Alternatively, you can execute the persistence operation indirectly through an EJB session bean or a managed bean.

Those examples should give you an idea of some of the tasks that are possible from within an Arquillian-enhanced test case. Now that you have plenty of motivation for using Arquillian, let's look at how to get started using Arquillian.