Over the past year, we have increasingly resorted to the use of EJBs to implement our business logic. In addition to all the benefits of using EJBs, we also ran into one of the issues. Due to things like dependency injection, automatic transaction management and JPA-based persistence, performing unit tests on EJBs is no easy task.
In order to still be able to perform testing on our EJBs, we initially decided to create a number of mock-objects, including a mock version of the EntityManager, and to perform the dependency injection manually. While this did allow us to perform unit tests on our EJBs, it also made our unit tests dependant on the internal implementation of the EJBs. Adding a newly injected dependency to a EJB would mean that the unit test needed to be expanded to also inject this dependency. Another issue was that since we were using a mock EntityManager, our tests were not covering our native SQL or JPQL queries or covering the JPA entity mappings. We also had no way of testing if transactions were correctly being rolled back or not.
We needed a way to perform our unit tests within an instance of the application server we use. This would solve many of the drawbacks of using mock-objects and performing manual dependency injection in the unit tests. Thankfully, an open source project named Arquillian provides a solution to these problems. Arquillian is an integration testing framework that can be used to perform testing on EJB’s or JPA code. Arquillian can be run either in conjunction JUnit or TestNG.
One of the disadvantages of using Arquillian, at least in our case and for the current Alpha 4 release, is that Maven or another dependency management tool is needed in order to run. Our main project does not use Maven, so we needed to find out a way of running Arquillian without using Maven.
The initial problem was to figure out the bare minimum set of libraries required to run Arquillian. This was achieved by manually going through the pom.xml files in the JBoss repository. This led us to the following minimum set of libraries required to run Arquillian:
Arquillian has very little in the way of configuration to determine to what type of container the test cases need to be deployed. Instead of using configuration, Arquillian uses a plug-in system to determine the type of container to deploy to. We needed to test our code in a JBoss 5.1 container, so we needed the plug-in for deploying to a managed JBoss 5.1 instance. This plug-in has a number of other dependencies. In order to actually be able to launch JBoss, the plug-in required the JBoss Server Manager library. Arquillian also requires a protocol implementation in order to execute the test cases once they have been deployed to the server. For JBoss 5.1, Arquillian requires the servlet 2.5 implementation. Lastly, in order to test EJB’s, we also needed the EJB and resource test enricher libraries. This lead us to the list of the following list of additional libraries required to run Arquillian using a managed JBoss 5.1 instance:
The managed JBoss 5.1 plugin also depends on the JBOSS_HOME environment variable being set to the directory where the JBoss instance that is to be used for testing is located. After we added all the above libraries to our testing classpath, we were finally able to run our Arquillian tests from our Ant scripts and from within Eclipse.
After we got our first unit tests running under Arquillian, we ran into a problem. Certain parts of our code check if the user is allowed to perform certain actions by checking if the user has a certain role or by checking the caller principal’s name. The user needs to have been authenticated before these parts of the code can be called. For testing, this means we needed to have a way of simulating a login by the user.
Arquillian calls the unit tests in a managed or remotely running container through a servlet in the web module of the test application. In order to do this Arquillian adds its own web module to the EAR file it deployes to the container. This web module needs to be configured for the correct security domain, but Arquillian doesn’t provide a way to add any files to the web module.
This web module is generated automatically by the protocol module being used, which in our case was the servlet 2.5 protcol. More specifically, the web module is being created by the createAuxiliaryArchive() in the class org.jboss.arquillian.protocol.servlet_2_5.ProtocolDeploymentAppender. We fixed the problem by creating a custom version of the servlet 2.5 protocol module in which we added our own custom jboss-web.xml file containing the correct security domain configuration. We then added a line to the createAuxiliaryArchive() method so that our configuration file would be included in the generated web module. Hopefully, future versions of Arquillian will add the functionality to customize the web module before deployment.