Arquillian - new testing platform

In this article, I would like to present you a pretty new testing platform called Arquillian. It works with Java EE, Spring and plenty of other technologies. I'm going to explain how it works and show you some of its features.

Introduction

Arquillian is a Java testing platform for writing integration and functional tests. It tries to test the code inside the container directly. When testing directly in container, you can easily access the database data using entity manager provided by the server. Arquillian is built on three main principles:

  • Tests should work on any supported container. It means that you don’t have to care, whether the test will be executed on Tomcat or WebLogic. This way, you can easily swap the container whenever you want, and tests should be easily runnable again. In other words, tests written using this technology should be aimed to test requirements and not specific deployment target (container).
  • Tests can be executed from IDE, but also from the build tool. This point is already included in JUnit and TestNG features.
  • Arquillian uses and extends existing test frameworks

Arquillian platform consists of several parts.

  • arquillian core itself is a machine that is able to fire and observe events.
  • test extension is built on the top of arquillian core, which is able to support the configuration after or before the tests are executed
  • test runners extension integrates existing test frameworks like JUnit, TestNG, Spock, JBehave, Cucumber or Thucydides.
  • container extension creates an interface for runtime providers (containers). Using this extension you can easily change on which container your tests are going to be deployed. It allows us to specify what should happen before/after deployment, before/after start etc. Container extension has several implementations (also known as container adapters), which provides specific functionality and implementation for concrete containers. Some of the supported containers are WildFly, Tomcat, Jetty, Spring, Weld, WebSphere etc. Moreover, we can deploy even to Android or iOS. We can see that it doesn’t matter if we use servlet container, java EE container or only bean container.
  • container – test extension listens for test events and fires container events. It acts as a binder between container and test environment worlds.

 

Practical overview

Let’s move from theory to practice. Below, you can see a simple Junit test case.

First we have to create simple calculation bean as a stub. As part of the next step we need to annotate our method using @Test annotation for it to be recognized by Junit. Lastly we could create a simple assertion for this functionality and our test is ready.

 

public class TestClass {
	
	private MyCalculationBean calcBean = new MyCalculationBeanStub();
	
	@Test
	public void beanShouldBePresent() {
		Assert.assertNotNull(calcBean);
	}
}

 

On the other hand, if we use Arquillian for the same test scenario the code will look like this.

 

@RunWith(Arquillian.class)
public class TestClass {
	
	@Deployment
	public static Archive<?> createDeployment() {
		return ShrinkWrap.create(WebArchive.class)
			.addXYZ(...);
	}
	
	@Inject
	private MyCalculationBean calcBean;
	
	@Test
	public void beanShouldBePresent() {
		Assert.assertNotNull(calcBean);
	}
}

 

As we can see some changes have been made. First of all, we annotated our test class with RunWith annotation. The Arquillian.class parameter tells arquillian to check this class for tests. Method createDeployment creates the archive, that can be deployed to the container we want to test in.

To be able to create a test archive for Arquillian, we have to use ShrinkWrap class. ShrinkWrap is a component that handles the test archive creation. In our case, we create the WebArchive type, which creates a standard deployable WAR archive. At the moment, it contains no resources or classes. By calling the addXYZ methods (addXYZ can be replaced by addClass, addPackage, addAsWebInf etc.), we add resources and classes to the archive, we need for our test scenario. This way, we can add persistence configuration (persistence.xml), web inf resources like web.xml, several classes, packages etc.

When our archive is created, we can use all the benefits it brings us. As in above mentioned example, we can see that we don’t need to create stubs for bean, but we can directly inject the bean, because our test will be executed inside the container. As we work inside the container, we do not need to create stubs, but we can inject the bean directly using bean container (Spring or CDI). Test method remains the same, because the way it works is already implemented inside the test framework.

In comparison to the standard Junit way, it’s clear that main approach of writing test methods remains the same whether we use the Arquillian or not. Only difference is the creation of the archive and ability to use the resources of the server (bean injection, datasources).

 

Test process

Now, that we have our first test written we have to do couple of things. First of all, Arquillian libraries should be present. We can do so manually or using some dependency/build tools like Maven, Gradle or Ivy. We have to define the core Arquillian dependencies and also the test framework integration (depends if we use TestNG, Junit or other supported one).

After all dependencies are set, we should choose which container we are going to use. We can choose from a plenty of container adapters that are provided by Arquillian. When chosen, we can specify our target server in profile part of Maven’s pom. In most of cases, the adapters are available in three server deployment scenarios you might need. These are embedded, managed and remote. Remote option assumes, that the container is up and running somewhere, and we don't have to manage it ourselves. When using managed mode, the starting, setting up operations and others are part of our Arquillian tests. In both options the container runs on a different JVM that our tests. The embedded option is the same as managed, but it runs on the same JVM.

When all dependencies and configurations are set, we can start our tests. After starting them, Arquillian builds and deploys the archive to the server, then it runs all tests and reports the results. The build and deploy phase, use before mentioned ShrinkWrap, which handles the deployment, resolves dependencies and descriptors. We have already seen the deployment part. The resolver is optional, but we can control directly from code, which dependencies of which version (for example from maven’s pom file) will be used. We can also define deployment descriptors in code using ShrinkWrap for builder's packaging phase.

Arquillian can execute tests in three modes:

  • it can run directly on the server and execute tests
  • it can test the interface provided by server (REST/SOAP)
  • or both

 

Extensions

Arquillian was developed to be extensible. Several useful extensions are developed by community and are provided as open source. Some of them are Graphene, Drone and Warp among many others. Graphene and Drone are based on WebDriver and Selenium tests and are used for web front end testing. Warp plugin is used for testing the REST services.

 

Other examples

This technology was initially created for use with Java EE technology stack (EJB, JSF, CDI etc. ), but in latest versions it became compatible also with Spring technology stack. In following examples, we are going to show you the Spring test cases, but also one Java EE sample.

 

Simple service injection (Spring)

In this example, we are going to demonstrate the Arquillian configuration and testing on a simple Spring service that is able to persist and update some JPA entities. I’m going to use JBoss based server for demonstrations, because I’m more familiar with it. And Junit as a test framework.

Imagine we have a JPA annotated class Car with id, brand_name and model properties. We want to make basic database operations with this entity.

On the top of it, there is defined a Spring repository that is used inside a Spring service. Example of such repository is shown below:

@Repository
public class CarRepository implements CarRepository {

@PersistenceContext
private EntityManager entityManager;

    public CarRepository() {

    }

    @Override
    public long save(Car car) {
        validate(car);
        entityManager.persist(car);
        return car.getId();
    }
	
    @Override
    public void update(Car car) {
        validate(car);
        entityManager.merge(car);
    }

    @Override
    public Car get(long id) {
        return entityManager.find(Car.class, id);
    }

...
}

 

We are basically using entity manager to get to database. For this test we only need to implement save, update and get methods.

Above this repository, there is a service defined, which looks as follows:

@Service
@Transactional
public class CarService implements CarService {

    @Autowired
    private CarRepository carRepository;

    public CarService() {

    }

    @Override
    public long save(Car car) {
        return carRepository.save(car);
    }

    @Override
    public void update(Car car) {
        carRepository.update(car);
    }

    @Override
    @Transactional(readOnly = true)
    public Car get(long id) {
        return carRepository.get(id);
    }
	
}

 

This service only wraps existing repository with its save, update and get methods. At this moment, we are ready to write tests for our code, but first we have to define configurations for persistence, spring and other.

First of all, I’m going to show you the arquillian.xml file which is essential for Arquillian. Our configuration looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.org/schema/arquillian"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="
        http://jboss.org/schema/arquillian
        http://jboss.org/schema/arquillian/arquillian_1_0.xsd">

    <defaultProtocol type="Servlet 3.0"/>

    <container qualifier="jbossas-managed" default="true">
        <configuration>
            <property name="jbossHome">target/jboss-as-7.1.1.Final</property>
            <property name="outputToConsole">true</property>
        </configuration>
    </container>

    <extension qualifier="spring-deployer">
        <property name="autoPackage">false</property>
    </extension>

</arquillian>

 As we can see, we define a managed JBoss AS server configuration and spring-deployer extension. In case of spring-deployer we don’t want to auto package build, because we want to do this operation from within the test suite.

When using spring, we should define the applicationContext.xml configuration file. At first, I define a bean for entity manager factory and corresponding component scan for our repository.

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="ArquillianSpringUnit"/>
</bean>

<context:component-scan base-package="nl.davinci.repository.impl"/>

 

 Now, we should define configuration for our service.

<tx:annotation-driven transaction-manager="txManager"/>

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<context:component-scan base-package="nl.davinci.service.impl"/>

 

We are going to assume in our configuration, that we have SQL files for create, delete, drop and insert database operations. Because we are using JBoss based server, we are going to define datasource for our database now.

<?xml version="1.0" encoding="UTF-8"?>
<datasources xmlns="http://www.jboss.org/ironjacamar/schema"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="
        http://www.jboss.org/ironjacamar/schema
http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
    <datasource enabled="true"
                jndi-name="jdbc/CarJDBCName"
                pool-name="EmbeddedH2Pool">
        <connection-url>jdbc:h2:mem:arquillian;DB_CLOSE_DELAY=-1</connection-url>
        <driver>h2</driver>
    </datasource>
</datasources>

 

To keep it simple, we are using H2 in memory database, that does not require any login etc. Over all this basic configuration, we further define persistence.xml and web.xml file, which I’m not going to show here because it’s trivial.

Let’s start with testing now. As we mentioned before, to be able to start testing in container, it is necessary to create an archive in which the tests will run when deployed to server.

@RunWith(Arquillian.class)
@Transactional(manager = "txManager")
@SpringConfiguration("applicationContext.xml")
public class CarServiceTestCase {

    @Deployment
    public static Archive createTestArchive() {
        return ShrinkWrap.create(WebArchive.class, "my-test.war")
                .addClasses(Car.class, CarRepository.class, CarService.class,
                        CarRepository.class, CarService.class)
                .addAsWebInfResource("jbossas-ds.xml")
                .addAsWebInfResource("web.xml")
                .addAsResource("applicationContext-repository.xml")
                .addAsResource("applicationContext-service.xml")
                .addAsResource("applicationContext.xml")
                .addAsResource("META-INF/persistence.xml")
                .addAsResource("create.sql")
                .addAsResource("delete.sql")
                .addAsResource("insert.sql")
                .addAsLibraries(springDependencies());
    }

    public static File[] springDependencies() {

        ArrayList files = new ArrayList();
        files.addAll(resolveDependencies("org.springframework:spring-context:3.1.1.RELEASE"));
        files.addAll(resolveDependencies("org.springframework:spring-orm:3.1.1.RELEASE"));
        files.addAll(resolveDependencies("org.springframework:spring-tx:3.1.1.RELEASE"));

        return files.toArray(new File[files.size()]);
    }

    public static List resolveDependencies(String artifactName) {
        MavenDependencyResolver mvnResolver = DependencyResolvers.use(MavenDependencyResolver.class);

        mvnResolver.loadMetadataFromPom("pom.xml");

        return Arrays.asList(mvnResolver.artifacts(artifactName).resolveAsFiles());
    }

    @Autowired
    private CarService stockService;

    @PersistenceContext
    private EntityManager entityManager;

    @After
    public void tearDown() throws Exception {

        entityManager.createQuery("delete from Car").executeUpdate();
    }

    @Test
    public void testSave() {
        Car yaris = new Car("Toyota", "Yaris");
        Car accord = new Car("Honda", "Accord");

        carService.save(yaris);
        carService.save(accord);

        assertTrue(yaris.getId() > 0);
        assertTrue(accord.getId() > 0);

        List cars = entityManager.createQuery("from Car").getResultList();

        assertEquals(2, cars.size());
    }

    @Test
    public void testUpdate() throws Exception {
        runScript(entityManager, "insert.sql");
        List cars = entityManager.createQuery("from Car").getResultList();

        Stock yaris = stocks.get(0);
        yaris.setModel("Corolla");

        carService.update(yaris);

        cars = entityManager.createQuery("from Car").getResultList();

        assertEquals(yaris.getModel(), stocks.get(0).getModel());
    }

 

At the begining, in method createDeployment we bundle the archive, which will be used for testing. We are using ShrinkWrap for this purpose. We can see that we create standard WAR archive. Then we add all necessary classes for our test like Car JPA class, service and repository. However, we are using JDBC in our test, so we had to add several resources for it like jbossas-ds (datasource) configuration, web.xml and persistence.xml files. If we want to be able to use the content of prepared SQL scripts we have to also add them as resources to our archive (insert, delete and create SQL files). Furthermore, the applicationContext.xml spring configuration is necessary too.

To demonstrate the deployer feature of ShrinkWrap I used also the addAsLibraries method, to add custom dependencies for spring framework. You can observe in method resolveDependencies, that I’m using ShrinkWrap’s Maven dependency resolver to get artifacts as files from the project’s Maven’s pom file and use them inside my test archive.

Great thing on custom creation of the archive is, that you can create it with only those classes and resources you only need.

To make this test case aware of the spring configuration file and transactional behavior, we define the @Transactional and @SpringConfiguration annotation on this class.

The testing itself, becomes very simple now. As you can see, we simply Autowire the CarService and inject EntityManager using @PersistenceContext annotation. At this moment, we are able to write tests for saving and updating functionality of the service, as we were developing standard methods inside the non-test part of the application.

 

Arquillian Drone extension for web frontend testing

The usage is pretty easy. All configuration options remain the same as in the previous example. All we need to do in configuration is to add a selenium extension to arquillian.xml file.

<extension qualifier="selenium">
    <property name="browser">*firefox</property>
</extension>

 

Now, if we have created some front end for example using JSF, we should add these front end files (xhtml) to our archive as web resources. When done we are able to inject a selenium driver into our test using @Drone annotation, as shown below.

@Drone
DefaultSelenium driver;

@ArquillianResource
URL deploymentUrl;

@Test
public void testLoginAndLogout() {
    Assert.assertNotNull(deploymentUrl);

    driver.open(deploymentUrl + "home.jsf");

    driver.type(USERNAME_FIELD, USERNAME);
    driver.type(PASSWORD_FIELD, PASSWORD);
    driver.click(LOGIN_BUTTON);
    driver.waitForPageToLoad(TIMEOUT);

    Assert.assertTrue(driver.isElementPresent(LOGGED_IN));

    driver.click(LOGOUT_BUTTON);
    driver.waitForPageToLoad(TIMEOUT);
    Assert.assertTrue(driver.isElementPresent(LOGGED_OUT));
}

 

The deployment URL of Arquillian can be different from the one we specified, so the resources that Arquillian uses (like urls or other paths) are injectable using @ArquillianResource annotation. As we can see the testing is then straightforward. This example shows testing of the login screen using Selenium plugin and Arquillian Drone.

 

Publikované: 11. jan 2016 13:05 | Počet prečítaní: 2584
  • Jakub Remenec

    Java Developer

    Jakub pred prácou v Davinci popri škole pracoval na viacerých projektoch s využitím JavaEE a Spring/GWT. Vo voľnom čase sa venuje skúmaniu nových technológii, cyklistike, turistike a hre na gitare. V minulosti sa tiež venoval akademickej debate.

We want you

Do you see yourself working with us? Check out our vacancies. Is your ideal vacancy not in the list? Please send an open application. We are interested in new talents, both young and experienced.

Join us