arquillian
Introduction to Testing with Arquillian
1. Overview
Arquillian is a container-agnostic integration testing framework for Java EE. Using Arquillian minimizes the burden of managing containers, deployments, framework initializations, and so on.
We can focus on writing actual tests and not on bootstrapping the test environment.
2. Core Concepts
Firstly, ShrinkWrap class provides an API to create deployable *.jar, *.war, and *.ear files.
Then, Arquillian allows us to configure the test deployment using the @Deployment annotation – on a method that returns a ShrinkWrap object.
2.2. Containers
-
Remote – tested using a remote protocol like JMX
-
Managed – remote containers but their lifecycle is managed by Arquillian
-
Embedded – local containers where tests are performed using local protocols
Also, we can classify containers by their capabilities:
-
Java EE applications deployed on an application server like Glassfish or JBoss
-
Servlet containers deployed on Tomcat or Jetty
-
Standalone containers
-
OSGI containers
It examines the runtime classpath and automatically selects the available container.
2.3. Test Enrichment
Arquillian enriches tests by providing e.g. the dependency injection so that we can write our tests easily.
We can inject dependencies using @Inject, inject resources with @Resource, EJB session beans using @EJB, etc.
2.4. Multiple Test Runners
@Deployment(name="myname" order = 1)
Where the name is the name of the deployment file and the order parameter is the execution order of the deployment, so we can now run tests on multiples deployments at the same time using the annotation:
@Test @OperateOnDeployment("myname")
The before test is executed on the myname deployment container using the order defined in the @Deployment annotation.
2.5. Arquillian Extensions
Arquillian offers multiple extensions in case our testing needs aren’t covered by the core runtime. We have persistence, transactions, client/server, REST extensions, etc.
We can enable those extensions by adding appropriate dependencies to Maven or Gradle config files.
Commonly used extensions are Drone, Graphene, and Selenium.
3. Maven Dependencies and Setup
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.1.13.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>4.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-glassfish-embedded-3.1</artifactId>
<version>1.0.0.Final</version>
<scope>test</scope>
</dependency>
The latest version of the dependencies can be found here: arquillian-bom, org.glassfish.main.extras, org.jboss.arquillian.container.
4. Simple Test
Let’s start with a simple component. We do not include any advanced logic here to be able to focus on tests:
public class Component {
public void sendMessage(PrintStream to, String msg) {
to.println(message(msg));
}
public String message(String msg) {
return "Message, " + msg;
}
}
Using Arquillian, we want to test that this class behaves correctly when invoked as a CDI bean.
4.2. Write Our First Arquillian Test
@RunWith(Arquillian.class)
If we’re going to run our tests inside a container, we need to use the @Deployment annotation.
Arquillian does not use the entire classpath to isolate the test archive. Instead, it uses the ShrinkWrap class, that is a Java API for creating archives. When we create the archive to test, we specify what files to include in the classpath to use the test. During the deployment, ShrinkWrap isolates only the classes needed for the test.
Using the addclass() method we can specify all necessary classes, and also add an empty manifest resource.
The JavaArchive.class creates a mockup web archive called test.war, this file is deployed into the container and then is used by Arquillian to perform tests:
@Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class)
.addClass(Component.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
Then we inject our component in the test:
@Inject
private Component component;
Finally, we perform our test:
assertEquals("Message, MESSAGE",component.message(("MESSAGE")));
component.sendMessage(System.out, "MESSAGE");
5. Testing Enterprise Java Beans
With Arquillian we can test dependency injection of an Enterprise Java Bean, to do that we create a class that has a method for converting any word to lowercase:
public class ConvertToLowerCase {
public String convert(String word){
return word.toLowerCase();
}
}
Using this class, we create a stateless class for calling the method created before:
@Stateless
public class CapsConvertor {
public ConvertToLowerCase getLowerCase(){
return new ConvertToLowerCase();
}
}
The CapsConvertor class gets injected into a service bean:
@Stateless
public class CapsService {
@Inject
private CapsConvertor capsConvertor;
public String getConvertedCaps(final String word){
return capsConvertor.getLowerCase().convert(word);
}
}
5.2. Test the Enterprise Java Bean
@Inject
private CapsService capsService;
@Test
public void givenWord_WhenUppercase_ThenLowercase(){
assertTrue("capitalize".equals(capsService.getConvertedCaps("CAPITALIZE")));
assertEquals("capitalize", capsService.getConvertedCaps("CAPITALIZE"));
}
Using ShrinkWrap, we ensure that all classes are wired correctly:
@Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(CapsService.class, CapsConvertor.class, ConvertToLowerCase.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
6. Testing JPA
@Entity
public class Car {
@Id
@GeneratedValue
private Long id;
@NotNull
private String name;
// getters and setters
}
We have a table that holds names of cars.
Then we are going to create our EJB to perform basic operations on our data:
@Stateless
public class CarEJB {
@PersistenceContext(unitName = "defaultPersistenceUnit")
private EntityManager em;
public Car saveCar(Car car) {
em.persist(car);
return car;
}
public List<Car> findAllCars() {
Query query
= em.createQuery("SELECT b FROM Car b ORDER BY b.name ASC");
List<Car> entries = query.getResultList();
return entries == null ? new ArrayList<>() : entries;
public void deleteCar(Car car) {
car = em.merge(car);
em.remove(car);
}
}
With saveCar we can save the car names into the database, we can get all cars stored with findAllCars, and also we can delete a car from the database with deleteCar.
6.2. Test Persistence with Arquillian
First, we add our classes to our ShrinkWrap:
.addClasses(Car.class, CarEJB.class)
.addAsResource("META-INF/persistence.xml")
Then we create our test:
@Test
public void testCars() {
assertTrue(carEJB.findAllCars().isEmpty());
Car c1 = new Car();
c1.setName("Impala");
Car c2 = new Car();
c2.setName("Lincoln");
carEJB.saveCar(c1);
carEJB.saveCar(c2);
assertEquals(2, carEJB.findAllCars().size());
carEJB.deleteCar(c1);
assertEquals(1, carEJB.findAllCars().size());
}
In this test, we first create four car instances, and we check that the number of rows in the database is the same we created.
8. Conclusion
-
introduced Arquillian core concepts
-
injected a component into the Arquillian test
-
tested an EJB
-
tested persistence
-
performed the Arquillian test using Maven
You can find the code from the article over on Github.