Go forth and test in-container!
Arquillian: A Component Model for Integration Testing - Part 3
The second difference is the @Deployment method. Since Arquillian is a container-oriented testing framework, it needs to be able to give the container something it can digest. For example, Java EE containers accept EARs, WARs and (EJB) JARs. In general, we can say that containers speak in archives.
In the past, integration testing (or perhaps system testing, depending on where you draw the line) meant having to rely on a build process to assemble an archive to deploy. Arquillian takes a different approach. Rather than having to package these archives somewhere on the file system, Arquillian leverages ShrinkWrap to allow you to produce the archive within the test itself. ShrinkWrap is a fluent API for creating archives as Java objects that exist in memory. Within the @Deployment method, the developer hand picks classes, resources, libraries and/or preexisting archives needed by the test, stuffs them into a ShrinkWrap archive and returns the result. Arquillian then takes over and begins the process of deploying the archive to the container.
The immediate benefit of using ShrinkWrap is that we don't have to rely on a build process to create the test archive that we are going to pass to the container. The test essentially prepares its own archive. Another benefit of using ShrinkWrap is that Arquillian can leverage its container integrations to more efficiently deploy the archive without having to write it out to the file system (not available with all containers).
After reading the archive from the @Deployment method, Arquillian appends its own resources, such as the test class, the test framework and extensions, and performs any other post-processing necessary. If the target container is managed by Arquillian, and the container is not yet started, Arquillian will setup and start the container (once per test suite). Once the container is ready, the Arquillian and ShrinkWrap adaptors for the container work together to translate the ShrinkWrap archive into a resource the container can read, perhaps by exporting it to a file or passing a stream to the container's deployment API.
Once the test archive is deployed, depending on the type (or profile) of the container, Arquillian may use either a remote or local protocol to invoke the test methods. Containers are a topic for another article, so we'll just briefly cover the different types so that you understand how the test gets executed.
2 Since Arquillian has an opportunity to modify the test archive prior to deployment, it means developers don’t have to add any special configuration (e.g., Servlet filters in web.xml) in order to get Arquillian to work. It just works.
3 Arquillian also has a client execution mode, which you activate by adding the @Run(AS_CLIENT) annotation to the test class. In this mode, Arquillian deploys the test archive, but leaves the test case behind to act as a remote client of the components being tested. This mode is useful for web testing, such as requesting a sequence of web pages or REST resources.
4 Test enrichment is not available in the client execution mode at the moment.
Standalone containers, such as the embedded EJB container, are executed in the same thread (and JVM) as the test runner. In this case, Arquillian employs a local protocol, which means it simply intercepts the test invocation, enriches the test case instance (which we'll talk about next), and allows execution to proceed. Containers with a web component, such as a Java EE container, require Arquillian to work over a remote protocol (the most common being HTTP). Arquillian forwards execution of each test method to the server, typically communicating with an HTTP Servlet that Arquillian plants into the test archive before it gets deployed. On the remote end, Arquillian bootstraps the test runner, creates a new instance of the test case, enriches it, invokes the test method and returns the outcome of the test, including any exceptions, back to the client (typically via HTML).
The final link in the chain is bridging the test case to the application's component model. That's the role of the @EJB annotation in this example.
The Component Model Link
In Java EE, the @EJB annotation is used as a hint on a field (or setter method) of an EJB to tell the container to assign (or inject) a reference to another EJB. Only, in this case, it's being used within the test class. And it's Arquillian that's doing the injecting. Arquillian intercepts the test invocation and satisfies the injection points (fields, setter methods and test method arguments) using a model consistent with the container being used. For instance, in a test case using JSR-299, Contexts and Dependency Injection for Java EE (CDI), Arquillian will satisfy the fields and methods annotated with @Inject. This step is called test enrichment.
By honoring the @EJB injection points in the test class, we've effectively brought the component model used in the application to the test environment. The test case is now one with the application. It speaks the same language as other consumers of the EJB we are testing. That's important because it simplifies the test, removes the use of a potentially non-portable JNDI name and allows us to test the class as an EJB component running in its intended environment.
This link is not just about dependency injection, though. It's about a shared component model made possible by running the test inside the container. There, the test has access to any resource the container provides. In a Java EE container, that includes resources in the naming directory (JNDI), environment entries, data sources, JMS destinations and so forth. In fact, these resources can be injected directly into the test using the @Resource annotation, also supported by Arquillian's EJB test enricher.
Let's consider a scenario that relies on a containerprovided resource. Assume we want to change the monthly payment calculation in the mortgage calculator so it reads the interest rate from an environment entry. First, we add the @Resource injection to one of the component's fields, shown in Listing ALL-6:
Next, we set the value of the interest rate environment variable using an ejb-jar.xml descriptor, which we create in the test resources directory. The resulting structure of this descriptor is displayed in Listing ALL-7.
We then package this descriptor into a test archive using ShrinkWrap, as shown in Listing ALL-8. Note we've switched to a WebArchive to work around a shortcoming in Arquillian.
We test the mortgage calculator component just as before (Listing ALL-5), and the container management and injection of the environment entry just works. That's why we say you can have as little or as much integration as you want. Since the end goal of testing is results, let's see how Arquillian hands back control to the test runner to report the outcome of the test.