Integration testing is very important in Java EE. The reason is two-fold:
- Business components often interact with resources or sub-system provided by the container
- Many declarative services get applied to the business component at runtime
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.
...or, what you test is what you run.
The reality is that you aren't really testing your component until you test it in situ. It's all to easy to create a test that puts on a good show but doesn't provide any real guarantee that the code under test functions properly in a production environment. The show typically involves mock components and/or bootstrapped environments that cater to the test. Such "unit tests" can't verify that the declarative services kick in as they should. While unit tests certainly have value in quickly testing algorithms and business calculations within methods, there still need to be tests that exercise the component as a complete service.
Rather than instantiating component classes in the test using Java's new operator, which is customary in a unit test, Arquillian allows you to inject the container-managed instance of the component directly into your test class (or you can look it up in JNDI) so that you are testing the actual component, just as it runs inside the application.
Do you really need to run the test in a real container when a Java SE CDI environment would do?
It's true, some tests can work without a full container. For instance, you can run certain tests in a Java SE CDI environment with Arquillian. Let's call these "standalone" tests, whereas tests which do require a full container are called "integration" tests. Every standalone test can also be run as an integration test, but not the other way around. While the standalone tests don't need a full container, it's also important to run them as integration tests as a final check just to make sure that there is nothing they conflict with (or have side effects) when run in a real container.
It might be a good strategy to make as many tests work in standalone mode as possible to ensure a quick test run, but ultimately you should consider running all of your tests in the target container. As a result, you'll likely enjoy a more robust code base.
We've established that integration testing is important, but how can integration testing being accomplished without involving every class in the application? That's the benefit that ShrinkWrap brings to Arquillian.
One huge advantage ShrinkWrap brings to Arquillian is classpath control. The classpath of a test run has traditionally been a kitchen sink of all production classes and resources with the test classes and resources layered on top. This can make the test run indeterministic, or it can just be hard to isolate test resources from the main resources.
Arquillian uses ShrinkWrap to create "micro deployments" for each test, giving you fine-grained control over what you are testing and what resources are available at the time the test is executed. An archive can include classes, resources and libraries. This not only frees you from the classpath hell that typically haunts test runners (Eclipse, Maven), it also gives you the option to focus on the interaction between an subset of production classes, or to easily swap in alternative classes. Within that grouping you get the self-assembly of services provided by Java EE---the very integration which is being tested.
Let's move on and consider some typical usage scenarios for Arquillian.