End-To-End Integration Testing For Kubernetes and OpenShift

Does the title leave you wondering, why you need integration tests for your deployments ?

If so, let me give you a few examples. Consider you decide to upgrade Kubernetes, deploy a new Zapier
integration or add some authentication capability. In order to ensure your platform works every single
time, all of the above scenarios need to be tested with robust integration tests.

With the advent of microservices and cloud native applications, adding integration or
end-to-end tests to your Kubernetes or OpenShift projects might be challenging and cumbersome especially
when you want to set up the test infrastructure to be as close as possible to production.

Arquillian Community understands this pain, and continuously strive to provide users a seamless
experience for writing integration tests with ease by bringing their tests to the real environment and
deploy with confidence like never before.

With this blog post, we aim at showcasing integration tests for your Kubernetes or OpenShift clusters using just Arquillian Cube. Moving a step further, we also demonstrate building and deploying from scratch, applications with no deployment configuration, leveraging the power of Fabric8 Maven Plugin along with the Arquillian Cube Extension.

The key point here is that if OpenShift or Kubernetes is used as deployable platform in production, your tests are executed in a the same environment as it will be in production, so your tests are even more real than before.

Further, the test cases are meant to consume and test the provided services and assert that the environment is in the expected state.

Deployment Testing Recipes

If, you wish to read no more and see it all in action, head straight to our specially curated
examples to help you get started with ease.

Example 1

Deploying a sample PHP Guestbook application with Redis on Kubernetes from the resource descriptor
manifest file and testing it using Arquillian Cube Extension for Kubernetes and Kubernetes custom assertions.

Source: arquillian-testing-microservices/kubernetes-deployment-testing

Example 2

Deploying a Wordpress and My SQL application to OpenShift from a Template file and testing it using Arquillian
Cube Extension for OpenShift and Fabric8 OpenShift Client.

Source: arquillian-testing-microservices/openshift-deployment-testing

Example 3

Building and deploying a sample SpringBoot GuestBook application with zero deployment configuration using
Fabric8 Maven Plugin and Arquillian Cube Extension .

Fabric8 Maven Plugin aids in building Docker images and creating Kubernetes and OpenShift resource
descriptors for the application that allows for a quick ramp-up with some opinionated defaults and Arquillian
Cube Extension deploys the application from the generated resource descriptors and then executes deployment tests.

Source: arquillian-testing-microservices/zero-config-deployment-test

Step By Step Guide To Writing Deployment Tests

For a more in-depth step by step coverage of deployment testing, continue reading below.

Step 1: Setting Up Kubernetes/OpenShift Cluster

One of the pre-requisites for Arquillian Kube Extension, is to have Kubernetes or OpenShift cluster running on
your host machine.

An easy way to setup Kubernetes or OpenShift cluster locally is using Minikube and Minishift respectively.

Step 2: Adding Arquillian Kube Dependencies to your project

Arquillian Kube Extension provides a black box approach to testing your deployment that neither
mutates the containers (by deploying, reconfiguring etc) nor the Kubernetes/OpenShift resources.

It is used for immutable infrastructure and integration testing, wherein the test cases are meant to,
consume and test the provided services and assert that the environment is in the expected state,
providing you with the confidence that your application will work correctly when deployed on
Kubernetes/OpenShift cluster.

Before we can start writing our tests, we need to define a few dependencies as shown below:

Arquillian Cube BOM – Unified Dependencies

<properties>
    <version.arquillian_cube>${latest_released_version}</version.arquillian_cube>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.arquillian.cube</groupId>
            <artifactId>arquillian-cube-bom</artifactId>
            <version>${version.arquillian_cube}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

Arquillian Cube Requirement

Arquillian optionally provides an `ArquillianConditionalRunner` to control situations under which your tests should be executed by letting you specify the requirements using annotations.
For example, you can use annotations like `@RequiresOpenshift` to skip test when the environment is not prepared to run the tests.

To configure these requirements for your tests, enable the dependency to the following module for your project.

<dependency>
    <groupId>org.arquillian.cube</groupId>
    <artifactId>arquillian-cube-requirement</artifactId>
    <scope>test</scope>
</dependency>

Arquillian Cube Kubernetes (For Kubernetes Deployment)

<dependency>
    <groupId>org.arquillian.cube</groupId>
    <artifactId>arquillian-cube-kubernetes</artifactId>
    <scope>test</scope>
</dependency>

Arquillian Cube OpenShift (For OpenShift Deployment)

<dependency>
    <groupId>org.arquillian.cube</groupId>
    <artifactId>arquillian-cube-openshift</artifactId>
    <scope>test</scope>
</dependency>

Arquillian JUnit

<dependency>
    <groupId>org.jboss.arquillian.junit</groupId>
    <artifactId>arquillian-junit-standalone</artifactId>
    <version>${latest_released_version}</version>
    <scope>test</scope>
</dependency>

Fabric8 OpenShift Client

<dependency>
    <groupId>io.fabric8</groupId>
    <artifactId>openshift-client</artifactId>
    <version>${latest_released_version}</version>
</dependency>

For Fabric8 OpenShift Client, include the above dependency in the pom.xml

Step 3: Writing Deployment Tests

Arquillian Cube extension provides out of the box functionality to create and manage a temporary namespace
per test suite for your tests and then applies all the required kubernetes/openshift resources as defined
in the resource descriptors generated by fabric8 maven plugin for your environment.

Kubernetes/OpenShift resources can then be made accessible within the Test Cases by injecting them using
Arquillian’s @ArquillianResources annotation (see example test below).

@RunWith(Arquillian.class)    (1)
public class ExampleTest {

    @Named("dummy")           (2)
    @PortForward
    @ArquillianResource
    Service dummyService;

    @ArquillianResource       (3)
    OpenShiftClient client;

    @RouteURL("application")  (4)
    @AwaitRoute
    private URL route;

    @Test
    public void service_instance_should_not_be_null() throws Exception {
        assertThat(service).isNotNull();
    }

    @Test
    public void test_at_least_one_pod() throws Exception {
       assertThat(client).pods().runningStatus().filterNamespace(session.getNamespace()).hasSize(1); (5)
    }

    @Test
    public void verify_route_is_configured_and_service_is_accessible() throws IOException {
        assertThat(route).isNotNull();
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().get().url(route).build();
        Response response = okHttpClient.newCall(request).execute();

        assertThat(response).isNotNull();
        assertThat(response.code()).isEqualTo(200);
    }
}

Explained below are the steps for the above snippet of a sample deployment test.

  1. Configuring Arquillian Test Runner
    To setup our test environment, we need to tell junit that this test shall be executed as a arquillian junit
    test. This is done by @RunWith(Arquillian.class).
  2. Injecting Deployment Resources within Test Cases
    Kubernetes/OpenShift resources can then be made accessible within the Test Cases by injecting them
    using Arquillian’s @ArquillianResources annotation.
    The resource providers available, can be used to inject to your test cases the following resources:
    • A kubernetes client as an instance of KubernetesClient.
    • Session object that contains information (e.g. the namespace) or the uuid of the test session.
    • Services (by id or as a list of all services created during the session, optionally filtered by label)
    • Deployments (by id or as a list of all deployments created during the session, optionally filtered by label)
    • Pods (by id or as a list of all pods created during the session, optionally filtered by label)
    • Replication Controllers (by id or as a list of all replication controllers created during the session,
      optionally filtered by label)
    • Replica Sets (by id or as a list of all replica sets created during the session, optionally filtered by label)
  3. The OpenShift extension also provides:
    • An openshift client as an instance of OpenShiftClient.
    • Deployment Configs (by id or as a list of all deployment configs created during the session)
    • Resources can be injected into test cases by id or as a list of all deployments created during the
      session, optionally filtered by label.
  4. Injecting Container Resources to access the deployed service
    Test Enrichers like @RouteURL further aid in injection of container resources like route to the deployed service.
    For farbric8 maven plugin to identify the route, @RouteURL should be set to artifactId of the project by
    default, or explicity configured otherwise.
  5. Adding Test Cases that assert environment is in the expected state.

Step 4: Using Assertion Libraries

Optionally, using Fabric8 Kubernetes Assertions , a nice library based on assert4j, aids in performing
meaningful and expressive assertions on top of the Kubernetes/OpenShift model.

To enable Fabric8 Kubernetes Assertions in your test, include the following dependency in the pom.xml

<dependency>
    <groupId>io.fabric8</groupId>
    <artifactId>kubernetes-assertions</artifactId>
    <version>${latest_released_version}</version>
    <scope>test</scope>
</dependency>

Once everything is ready, Arquillian Kube runs your tests, enriched with resources required to access service
and finally cleaning up everything after the testing is over.

For more details and available configuration options check arquillian kube documentation.

Building Docker Images and creating Resource Descriptors.

Optionally, if you just have a Java application that you wish you to bring to Kubernetes or OpenShift,
use Fabric8 Maven Plugin to create docker images and resource descriptors for you.

Fabric8 Maven Plugin makes Kubernetes/OpenShift look and feel like an application server to a Java
developer by letting you build and deploy your application from maven just like you would with other
maven plugins.

To enable fabric8 on your existing maven project just type fabric8:setup command which adds the
fabric8-maven-plugin to your pom.xml.

Alternatively, you can manually add the following plugin definition to your pom.xml file:

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>fabric8-maven-plugin</artifactId>
    <version>3.5.32</version>

    <!-- Connect fabric8:resource and fabric8:build to lifecycle phases -->
    <executions>
        <execution>
            <id>fmp</id>
            <phase>package</phase>
               <goals>
                    <goal>resource</goal>
                    <goal>build</goal>
                </goals>
        </execution>
    </executions>
</plugin>

For more and complete configuration details check out fabric8 maven plugin documentation.

Summary

With some basic features, simple steps and specially crafted examples as highlighted above, you can easily get started with Arquillian Cube extension to test your applications in real production environments, be it Kubernetes or OpenShift clusters, without worrying about setting up the infrastructure and only focusing on the core test logic.

Arquillian Core 1.0.0.Alpha5 Released

Since we wrote this post we didn't laze around. Check our latest announcement.

The Arquillian team is proud to announce the 1.0.0.Alpha5 release of the Arquillian Core component!

After a long wait we can finally give you some good news.

drum roll…

Arquillian 1.0.0.Alpha5 has been released!

In the beginning of the cycle we came to the conclusion that the old Arquillian core just did not cut it in respect to where we were heading, so big parts of it has been rewritten…

Some of the highlights in this release:

  • DeploymentException assertion – Verify that a @Deployment throws the expected deployment exception using @ShouldThrowException(Exception.class)
@Deployment @ShouldThrowException(WeldException.class)
public static WebArchive createTestDeployment() { }
  • Multiple deployments – Define as many @Deployment methods as you may need. If you need them deployed in order, use @Deployment.order. When dealing with multiple @Deployments you have to specify which deployment context a @Test method should run within by using the @OperateOnDeployment("deploymentName"). The deploymentName is specified using @Deployment.name. With this you can swap between in container testing in one deployment, @RunAsClient in the context of another deployment and back incontainer in the third.
@Deployment(order = 1, name = "dep1")
public static WebArchive createTestDeployment() { }
 
@Deployment(order = 2, name = "dep2")
public static WebArchive createTestDeployment2() { }
 
@Test @OperateOnDeployment("dep1")
public void callActive1() throws Exception { }
 
@Test @OperateOnDeployment("dep2")
public void callActive1() throws Exception { }
  • Multiple containers – Deploy multiple deployments to multiple containers in the same test class using @TargetsContainer("containerName") on the @Deployment methods. Combined with @OperateOnDeployment("name") individual @Test methods can now execute in different containers.
@Deployment(name = "dep1") @TargetsContainer("node-1")
public static WebArchive createTestDeployment() { }
 
@Deployment(name = "dep2") @TargetsContainer("node-2")
public static WebArchive createTestDeployment2() { }
 
@Test @OperateOnDeployment("dep1")
public void callActive1() throws Exception { }
 
@Test @OperateOnDeployment("dep2")
public void callActive1() throws Exception { }
  • Configurable protocol – Previously the protocol was bound to the container you were running on. The container still has a default, but this can now be overwritten on a pr @Deployment method level by using the annotation @OverProtocol("protocolName").
@Deployment(name = "dep1") @TargetsContainer("node-1") @OverProtocol("Servlet 3.0")
public static WebArchive createTestDeployment() { }
 
@Deployment(name = "dep2") @TargetsContainer("node-2") @OverProtocol("EJB 3.1")
public static WebArchive createTestDeployment2() { }
 
@Test @OperateOnDeployment("dep1") // in container text execution is done over HTTP
public void callActive1() throws Exception { }
 
@Test @OperateOnDeployment("dep2") // in container text execution is done over RMI
public void callActive1() throws Exception { }
  • Descriptor deployment – Need to deploy a JMS Queue, or a DataSource? Use the Desciptor deployment. Works the same as a Archive deployment by defining a deployment method with return type Descriptor.
@Deployment
public static Descriptor createTestDeployment() { }
  • Arquillian Drone – A new extension for Web testing. Integrates Arquillian with Selenium, WebDriver and Arquillian Ajocado.
@RunWith(Arquillian.class)
public class AjocadoTestCase {
   // load ajocado driver
   @Drone
   AjaxSelenium driver;
}

Some changes:

  • @Run(AS_CLIENT) and @Run(IN_CONTAINER) have been replaced by @RunAsClient. RunMode is default read from @Deployment.testable@, but you can override the run mode for a in-container deployment using @RunAsClient on the @Test method.
  • New Configuration XML format
  • GlassFish 3.0 support was replaced with 3.1 support.

Big thanks to the Arquillian and ShrinkWrap community for helping us with this release!

A extra goes out to, Karel Piwko for Arquillian Drone, Jason Porter for the GlassFish Remote 3.1 container and David R Allen for other random issues.

[ Issues | Javadoc: API, SPI | Reference Guide | Release Notes | Maven artifacts ]

What is Arquillian?

Arquillian is open source software that empowers you to test JVM-based applications more effectively. Created to defend the software galaxy from bugs, Arquillian brings your test to the runtime so you can focus on testing your application's behavior rather than managing the runtime. Using Arquillian, you can develop a comprehensive suite of tests from the convenience of your IDE and run them in any IDE, build tool or continuous integration environment.

Release details

Component Arquillian Core
Version 1.0.0.Alpha5 view tag
Release date 2011-03-18
Released by Aslak Knutsen
Compiled against

Published artifacts org.jboss.arquillian

  • org.jboss.arquillian » arquillian-api jar javadoc pom
  • org.jboss.arquillian » arquillian-spi jar javadoc pom
  • org.jboss.arquillian » arquillian-impl-base jar javadoc pom
  • org.jboss.arquillian » arquillian-junit jar javadoc pom
  • org.jboss.arquillian » arquillian-testng jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-cdi jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-ejb jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-osgi jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-resource jar javadoc pom
  • org.jboss.arquillian.protocol » arquillian-protocol-servlet jar javadoc pom
  • org.jboss.arquillian.protocol » arquillian-protocol-jmx jar javadoc pom
  • org.jboss.arquillian.protocol » arquillian-protocol-jmx-osgi jar javadoc pom

Release notes and resolved issues 64

Feature Request
  • ARQ-67 - Need to be able to deploy resources to the container alongside the primary deployment
  • ARQ-152 - Support multiple container configurations for same container type
  • ARQ-153 - Protocol configuration element should be separate from Container
  • ARQ-158 - Replace method arguments with toString instead of Class
  • ARQ-167 - Support @EJB.mappedName for TestClass injection
  • ARQ-168 - Validation on container configuration properties
  • ARQ-196 - Should support controlling multiple Containers
  • ARQ-215 - Configuration should support loading of Configuration data for extensions/frameworks
  • ARQ-218 - ServiceLoader should support Default implementations
  • ARQ-227 - Support Deployment exception assert
  • ARQ-283 - Support loading of configuration for Arquillian-Selenium
  • ARQ-299 - Create a IN_CONTAINER Exception Proxy
  • ARQ-309 - Allow configuration to specify an OpenEJB configuration resources (openejb.xml)
  • ARQ-310 - Add a post-construct method to ContainerConfiguration
  • ARQ-313 - ARQ should support Multi-module (Multiple WAR deployments) testing
  • ARQ-316 - more complete support for servlet 2.5
  • ARQ-319 - Allow container START_TIME to be configurable in arquillian.xml
  • ARQ-323 - Implement a GlassFish 3.1 remote container based on REST API
  • ARQ-326 - Track JBoss AS Final
  • ARQ-329 - Support Ajocado in Selenium extension
  • ARQ-346 - Create a GlassFish 3.1 Embedded Container
  • ARQ-349 - Create a Protocol processor SPI for modifying the final deployment generated by the DeploymentPackager
  • ARQ-353 - Remove DeploymentScanner disabling
  • ARQ-360 - Honor system property for exporting test archives
  • ARQ-362 - @Run(AS_CLIENT) support on @Test
  • ARQ-367 - Add support for @ArquillianResource
  • ARQ-371 - Split Arquillian Selenium configuration according to framework
  • ARQ-373 - Support multiple Web Test objects in one test
  • ARQ-378 - For managed appservers, a configurable "is it up?" URL would be nice
  • ARQ-380 - Core should support AroundInvoke style handlers of Events
  • ARQ-383 - rename MaxDeploymentsBeforeRestart to maxTestClassesBeforeRestart
  • ARQ-387 - Selenium extension should use the TestEnricher SPI to do injection into the test case
  • ARQ-389 - Rename @Target, @Expected, @Run and @DeploymentTarget annotations
Bug
  • ARQ-57 - JBossAS Remote Containers Depend upon Sun JDK
  • ARQ-110 - RunMode Local should reuse protocol-local
  • ARQ-124 - Move jndi.properties out as Configuration
  • ARQ-164 - NPE in DeployableTestBuilder
  • ARQ-171 - ServletMethodExecutor should get context path from container
  • ARQ-211 - Protocol Servlet should be automatically registered for Tomcat Embedded 6
  • ARQ-217 - Servlet 2.5 Protocol should support Application WebArchives
  • ARQ-275 - WeldSEContainer doesn't meet Weld 1.1 SPI contract
  • ARQ-281 - NPE when JBOSS_HOME isn't set
  • ARQ-289 - All poms refere to old svn repo, update to git
  • ARQ-290 - performence/pom.xml references WELD-1.0.1
  • ARQ-292 - Enforcing Maven 3 in build/pom.xml does not seem to work...
  • ARQ-298 - Implement conversations based on the new Weld context management API
  • ARQ-304 - String based properties cannot be loaded through System properties
  • ARQ-330 - Container Reference for Weld EE Embedded use 1.0.1.SP1 in example, should be 1.1.0.Beta1
  • ARQ-335 - Weld SE container does not properly load extension classes at boot
  • ARQ-340 - mappedName and lookup attributes are ignored for @EJB in jections into test cases, forcing a naming convention on implementations
  • ARQ-352 - ArquillianDescriptor should support configuration of extensions
  • ARQ-356 - JBoss AS Managed does not allow to set RMI port used for deployment. Forces users to use 1099
  • ARQ-372 - The @EJB annotation does not work in a TestCase that extends abstract class
  • ARQ-377 - Reloaded Container test is failing; MCServer and ShrinkWrapDeployer can't bind to correct scope
  • ARQ-379 - Arquillian does not allow any configuration of OpenEJB
  • ARQ-392 - impl-base does not export resolver-maven-impl dep
Task
  • ARQ-192 - Install OSGi bundles in memory
  • ARQ-259 - Provide xsd for all containers and for core
  • ARQ-291 - Create Selenium extension
  • ARQ-370 - Merge remote aslakknutsen/the_bigger_picture back into upstream/master
  • ARQ-374 - Renaming Selenium extension to more general name
  • ARQ-384 - Prepare Alpha-5 release
  • ARQ-388 - Update Selenium version to 2.0b2
  • ARQ-393 - Update Arquillian Drone Docbook

Thanks to the following list of contributors: Aslak Knutsen, Karel Piwko, Andrew Lee Rubinger, David R. Allen, Andy Gibson, Dan Allen, Jason Porter

Arquillian Core 1.0.0.Alpha5 Released

Since we wrote this post we didn't laze around. Check our latest announcement.

The Arquillian team is proud to announce the 1.0.0.Alpha5 release of the Arquillian Core component!

After a long wait we can finally give you some good news.

drum roll…

Arquillian 1.0.0.Alpha5 has been released!

In the beginning of the cycle we came to the conclusion that the old Arquillian core just did not cut it in respect to where we were heading, so big parts of it has been rewritten…

Some of the highlights in this release:

  • DeploymentException assertion – Verify that a @Deployment throws the expected deployment exception using @ShouldThrowException(Exception.class)
@Deployment @ShouldThrowException(WeldException.class)
public static WebArchive createTestDeployment() { }
  • Multiple deployments – Define as many @Deployment methods as you may need. If you need them deployed in order, use @Deployment.order. When dealing with multiple @Deployments you have to specify which deployment context a @Test method should run within by using the @OperateOnDeployment("deploymentName"). The deploymentName is specified using @Deployment.name. With this you can swap between in container testing in one deployment, @RunAsClient in the context of another deployment and back incontainer in the third.
@Deployment(order = 1, name = "dep1")
public static WebArchive createTestDeployment() { }
 
@Deployment(order = 2, name = "dep2")
public static WebArchive createTestDeployment2() { }
 
@Test @OperateOnDeployment("dep1")
public void callActive1() throws Exception { }
 
@Test @OperateOnDeployment("dep2")
public void callActive1() throws Exception { }
  • Multiple containers – Deploy multiple deployments to multiple containers in the same test class using @TargetsContainer("containerName") on the @Deployment methods. Combined with @OperateOnDeployment("name") individual @Test methods can now execute in different containers.
@Deployment(name = "dep1") @TargetsContainer("node-1")
public static WebArchive createTestDeployment() { }
 
@Deployment(name = "dep2") @TargetsContainer("node-2")
public static WebArchive createTestDeployment2() { }
 
@Test @OperateOnDeployment("dep1")
public void callActive1() throws Exception { }
 
@Test @OperateOnDeployment("dep2")
public void callActive1() throws Exception { }
  • Configurable protocol – Previously the protocol was bound to the container you were running on. The container still has a default, but this can now be overwritten on a pr @Deployment method level by using the annotation @OverProtocol("protocolName").
@Deployment(name = "dep1") @TargetsContainer("node-1") @OverProtocol("Servlet 3.0")
public static WebArchive createTestDeployment() { }
 
@Deployment(name = "dep2") @TargetsContainer("node-2") @OverProtocol("EJB 3.1")
public static WebArchive createTestDeployment2() { }
 
@Test @OperateOnDeployment("dep1") // in container text execution is done over HTTP
public void callActive1() throws Exception { }
 
@Test @OperateOnDeployment("dep2") // in container text execution is done over RMI
public void callActive1() throws Exception { }
  • Descriptor deployment – Need to deploy a JMS Queue, or a DataSource? Use the Desciptor deployment. Works the same as a Archive deployment by defining a deployment method with return type Descriptor.
@Deployment
public static Descriptor createTestDeployment() { }
  • Arquillian Drone – A new extension for Web testing. Integrates Arquillian with Selenium, WebDriver and Arquillian Ajocado.
@RunWith(Arquillian.class)
public class AjocadoTestCase {
   // load ajocado driver
   @Drone
   AjaxSelenium driver;
}

Some changes:

  • @Run(AS_CLIENT) and @Run(IN_CONTAINER) have been replaced by @RunAsClient. RunMode is default read from @Deployment.testable@, but you can override the run mode for a in-container deployment using @RunAsClient on the @Test method.
  • New Configuration XML format
  • GlassFish 3.0 support was replaced with 3.1 support.

Big thanks to the Arquillian and ShrinkWrap community for helping us with this release!

A extra goes out to, Karel Piwko for Arquillian Drone, Jason Porter for the GlassFish Remote 3.1 container and David R Allen for other random issues.

[ Issues | Javadoc: API, SPI | Reference Guide | Release Notes | Maven artifacts ]

What is Arquillian?

Arquillian is open source software that empowers you to test JVM-based applications more effectively. Created to defend the software galaxy from bugs, Arquillian brings your test to the runtime so you can focus on testing your application's behavior rather than managing the runtime. Using Arquillian, you can develop a comprehensive suite of tests from the convenience of your IDE and run them in any IDE, build tool or continuous integration environment.

Release details

Component Arquillian Core
Version 1.0.0.Alpha5 view tag
Release date 2011-03-18
Released by Aslak Knutsen
Compiled against

Published artifacts org.jboss.arquillian

  • org.jboss.arquillian » arquillian-api jar javadoc pom
  • org.jboss.arquillian » arquillian-spi jar javadoc pom
  • org.jboss.arquillian » arquillian-impl-base jar javadoc pom
  • org.jboss.arquillian » arquillian-junit jar javadoc pom
  • org.jboss.arquillian » arquillian-testng jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-cdi jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-ejb jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-osgi jar javadoc pom
  • org.jboss.arquillian.testenricher » arquillian-testenricher-resource jar javadoc pom
  • org.jboss.arquillian.protocol » arquillian-protocol-servlet jar javadoc pom
  • org.jboss.arquillian.protocol » arquillian-protocol-jmx jar javadoc pom
  • org.jboss.arquillian.protocol » arquillian-protocol-jmx-osgi jar javadoc pom

Release notes and resolved issues 64

Feature Request
  • ARQ-67 - Need to be able to deploy resources to the container alongside the primary deployment
  • ARQ-152 - Support multiple container configurations for same container type
  • ARQ-153 - Protocol configuration element should be separate from Container
  • ARQ-158 - Replace method arguments with toString instead of Class
  • ARQ-167 - Support @EJB.mappedName for TestClass injection
  • ARQ-168 - Validation on container configuration properties
  • ARQ-196 - Should support controlling multiple Containers
  • ARQ-215 - Configuration should support loading of Configuration data for extensions/frameworks
  • ARQ-218 - ServiceLoader should support Default implementations
  • ARQ-227 - Support Deployment exception assert
  • ARQ-283 - Support loading of configuration for Arquillian-Selenium
  • ARQ-299 - Create a IN_CONTAINER Exception Proxy
  • ARQ-309 - Allow configuration to specify an OpenEJB configuration resources (openejb.xml)
  • ARQ-310 - Add a post-construct method to ContainerConfiguration
  • ARQ-313 - ARQ should support Multi-module (Multiple WAR deployments) testing
  • ARQ-316 - more complete support for servlet 2.5
  • ARQ-319 - Allow container START_TIME to be configurable in arquillian.xml
  • ARQ-323 - Implement a GlassFish 3.1 remote container based on REST API
  • ARQ-326 - Track JBoss AS Final
  • ARQ-329 - Support Ajocado in Selenium extension
  • ARQ-346 - Create a GlassFish 3.1 Embedded Container
  • ARQ-349 - Create a Protocol processor SPI for modifying the final deployment generated by the DeploymentPackager
  • ARQ-353 - Remove DeploymentScanner disabling
  • ARQ-360 - Honor system property for exporting test archives
  • ARQ-362 - @Run(AS_CLIENT) support on @Test
  • ARQ-367 - Add support for @ArquillianResource
  • ARQ-371 - Split Arquillian Selenium configuration according to framework
  • ARQ-373 - Support multiple Web Test objects in one test
  • ARQ-378 - For managed appservers, a configurable "is it up?" URL would be nice
  • ARQ-380 - Core should support AroundInvoke style handlers of Events
  • ARQ-383 - rename MaxDeploymentsBeforeRestart to maxTestClassesBeforeRestart
  • ARQ-387 - Selenium extension should use the TestEnricher SPI to do injection into the test case
  • ARQ-389 - Rename @Target, @Expected, @Run and @DeploymentTarget annotations
Bug
  • ARQ-57 - JBossAS Remote Containers Depend upon Sun JDK
  • ARQ-110 - RunMode Local should reuse protocol-local
  • ARQ-124 - Move jndi.properties out as Configuration
  • ARQ-164 - NPE in DeployableTestBuilder
  • ARQ-171 - ServletMethodExecutor should get context path from container
  • ARQ-211 - Protocol Servlet should be automatically registered for Tomcat Embedded 6
  • ARQ-217 - Servlet 2.5 Protocol should support Application WebArchives
  • ARQ-275 - WeldSEContainer doesn't meet Weld 1.1 SPI contract
  • ARQ-281 - NPE when JBOSS_HOME isn't set
  • ARQ-289 - All poms refere to old svn repo, update to git
  • ARQ-290 - performence/pom.xml references WELD-1.0.1
  • ARQ-292 - Enforcing Maven 3 in build/pom.xml does not seem to work...
  • ARQ-298 - Implement conversations based on the new Weld context management API
  • ARQ-304 - String based properties cannot be loaded through System properties
  • ARQ-330 - Container Reference for Weld EE Embedded use 1.0.1.SP1 in example, should be 1.1.0.Beta1
  • ARQ-335 - Weld SE container does not properly load extension classes at boot
  • ARQ-340 - mappedName and lookup attributes are ignored for @EJB in jections into test cases, forcing a naming convention on implementations
  • ARQ-352 - ArquillianDescriptor should support configuration of extensions
  • ARQ-356 - JBoss AS Managed does not allow to set RMI port used for deployment. Forces users to use 1099
  • ARQ-372 - The @EJB annotation does not work in a TestCase that extends abstract class
  • ARQ-377 - Reloaded Container test is failing; MCServer and ShrinkWrapDeployer can't bind to correct scope
  • ARQ-379 - Arquillian does not allow any configuration of OpenEJB
  • ARQ-392 - impl-base does not export resolver-maven-impl dep
Task
  • ARQ-192 - Install OSGi bundles in memory
  • ARQ-259 - Provide xsd for all containers and for core
  • ARQ-291 - Create Selenium extension
  • ARQ-370 - Merge remote aslakknutsen/the_bigger_picture back into upstream/master
  • ARQ-374 - Renaming Selenium extension to more general name
  • ARQ-384 - Prepare Alpha-5 release
  • ARQ-388 - Update Selenium version to 2.0b2
  • ARQ-393 - Update Arquillian Drone Docbook

Thanks to the following list of contributors: Aslak Knutsen, Karel Piwko, Andrew Lee Rubinger, David R. Allen, Andy Gibson, Dan Allen, Jason Porter

The perfect recipe for testing JPA 2, revisited

A while ago, Arun Gupta proposed a recipe for testing JPA 2 (JPQL & Criteria) using Embedded GlassFish in one of his notable Tips of The Day (TOTD #133). Embedded containers such as GlassFish certainly make testing Java EE APIs achievable. But I want to challenge Arun’s conclusion that using Embedded GlassFish programmatically is the perfect recipe for testing.

In this entry, I’ll show that the test can be further simplified. By throwing the complexity of managing the container over the wall, you can focus solely on the task at hand, testing (and experimenting with) JPA 2. Not only does the test get simpler, it also becomes portable, so you are not locked into running it on Embedded GlassFish. Any compliant Java EE container, such as JBoss AS, or even a standalone JPA runtime will do. That’s a lot of flexibility.

The secret ingredient: Arquillian

As in Arun’s TOTD, our test will:

  • persist entities to a database and subsequently query them using JPQL and the JPA 2 Criteria API

But that’s all we’ll worry about. We’ll let Arquillian handle the task of creating the JDBC Connection Pool and JDBC Resource using GlassFish APIs. Even that is behavior specific to the select target container. Other target containers may have parallel operations. That’s of no concern to the test.

Like Arun’s application, ours uses a (video) Game entity with two fields:

  • id – the primary key
  • title – the title of the game

The test persists 3 sample entries to the database and then retrieves them using a JPQL statement and the Criteria API. The test will perform three tasks:

  • store 3 sample entities in the database using the JPA EntityManager
  • query the database using JPQL
  • query the database using Criteria API

The entire source code is available in the Arquillian examples project on github. All you need to see the action is run “mvn test” (and a hint of patience to wait for Maven to download the dependencies).

To get you acclimated, here’s the directory structure of the project.

pom.xml
src
|-- main
|   `-- java
|       `-- com
|           `-- acme
|               `-- jpa
|                   `-- Game.java
`-- test
    |-- java
    |   `-- com
    |       `-- acme
    |           `-- jpa
    |               `-- GamePersistenceTestCase.java
    |-- resources
    |   `-- arquillian.xml
    |-- resources-glassfish-embedded
    |   |-- sun-resources.xml
    |   `-- test-persistence.xml
    `-- resources-jbossas-remote
        |-- jndi.properties
        `-- test-persistence.xml

Game is the JPA entity class and test-persistence.xml provides the definition of our Persistence Unit for the test environment. We won’t touch persistence.xml since that’s the definition for the production environment.

Notice we have resource directories for both Embedded GlassFish and remote JBoss AS. We’ll get into that later.

Here’s the source of the Game entity class, as denoted by the @Entity annotation:

src/main/resources/com/acme/jpa/Game.java
package com.acme.jpa;
 
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
 
@Entity
public class Game implements Serializable {
    private Long id;
    private String title;
 
    public Game() {}
 
    public Game(String title) {
        this.title = title;
    }
 
    @Id @GeneratedValue
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    @NotNull
    @Size(min = 3, max = 50)
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String name) {
        this.title = name;
    }
 
    @Override
    public String toString() {
        return "Game@" + hashCode() + "[id = " + id + "; title = " + title + "]";
    }
}

The primary key is defined using the @Id annotation on the field. Additional columns are derived automatically from bean properties (standard getter/setter convention). You can use the @Column annotation to explicitly set the name of the column. Otherwise, the column name is determined by removing the “get” prefix from the bean property’s read method and lowercasing the first character of the remainder (e.g., getTitle() => title).

We are also using standard Bean Validation annotations to enforce constraints. Here, a title must be provided and it must be between 3 and 50 characters long. That would make a good test.

Let’s create a new JUnit 4 Arquillian test case, GamePersistenceTestCase, and prepare it to test our JPA operations. We’ll leverage CDI to supply us with the resources we need via dependency injection. (We’ll look at an alternative way to accomplish this using a utility EJB in a follow-up post).

src/test/java/com/acme/jpa/test/GamePersistenceTestCase.java
@RunWith(Arquillian.class)
public class GamePersistenceTestCase {
    @Deployment
    public static Archive<?> createDeployment() {
        return ShrinkWrap.create(WebArchive.class, "test.war")
            .addPackage(Game.class.getPackage())
            .addManifestResource("test-persistence.xml", "persistence.xml")
            .addWebResource(EmptyAsset.INSTANCE, "beans.xml");
    }
 
    private static final String[] GAME_TITLES = {
        "Super Mario Brothers",
        "Mario Kart",
        "F-Zero"
    };
    
    @PersistenceContext
    EntityManager em;
    
    @Inject
    UserTransaction utx;
 
    // tests go here
}

Let’s work from top to bottom to understand what’s going on here before we get to the tests.

@RunWith(Arquillian.class)
Tells JUnit to delegate execution of the test to the Arquillian runner. This allows Arquillian to infuse your test with a component model, which consists of container lifecycle management and dependency injection, among other enhancements. Notice that you are not required to extend a base class, so that’s left open to your own design.
@Deployment method
Produces a “micro deployment” archive using the ShrinkWrap API. Arquillian deploys this archive, along with the test case and some additional infrastructure, to the container. The test then executes as a component within this mini application. The contents of this archive are the tests isolated little world.
GAME_TITLES constant
The sample test data
PersistenceContext EntityManager
Injects the persistence context (EntityManager) directly into the test, just as though the test were a managed bean.
@Inject UserTransaction
Injects a JTA transaction directly into the test, a service provided to the managed bean by CDI (JSR-299).
Let’s add a helper method that enters the sample records into the database:
public void insertSampleRecords() throws Exception {
    // clear database
    utx.begin();
    em.joinTransaction();
 
    System.out.println("Clearing the database...");
    em.createQuery("delete from Game").executeUpdate();
 
    // insert records
    System.out.println("Inserting records...");
    for (String title : GAME_TITLES) {
        Game game = new Game(title);
        em.persist(game);
    }
 
    utx.commit();
}

We have to explicitly enlist the EntityManager in the JTA transaction since we are using these two resources independently. Normally enlistment happens automatically within an EJB.

Here’s the test that verifies we can select the sample records using JPQL. We’ll print some logging statements so you can watch what’s going on.

@Test
public void should_be_able_to_select_games_using_jpql() throws Exception {
    insertSampleRecords();
 
    utx.begin();
    em.joinTransaction();
 
    System.out.println("Selecting (using JPQL)...");
    List<Game> games = em.createQuery("select g from Game g order by g.id",
       Game.class).getResultList();
    System.out.println("Found " + games.size() + " games (using JPQL)");
    assertEquals(GAME_TITLES.length, games.size());
 
    for (int i = 0; i < GAME_TITLES.length; i++) {
        assertEquals(GAME_TITLES[i], games.get(i).getTitle());
        System.out.println(games.get(i));
    }
 
    utx.commit();
}

Now for the new stuff! Here’s the same test that uses the Criteria API. Note that this test depends on the JPA 2 annotation processor generating the Game_ metamodel class during the build compilation step.

@Test
public void should_be_able_to_select_games_using_criteria_api() throws Exception {
    insertSampleRecords();
 
    utx.begin();
    em.joinTransaction();
 
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Game> criteria = builder.createQuery(Game.class);
    // FROM clause
    Root<Game> game = criteria.from(Game.class);
    // SELECT clause
    criteria.select(game);
    // ORDER BY clause
    criteria.orderBy(builder.asc(game.get(Game_.id)));
    // No WHERE clause, select all
 
    System.out.println("Selecting (using Criteria)...");
    List<Game> games = em.createQuery(criteria).getResultList();
    System.out.println("Found " + games.size() + " games (using Criteria)");
    assertEquals(GAME_TITLES.length, games.size());
 
    for (int i = 0; i < GAME_TITLES.length; i++) {
        assertEquals(GAME_TITLES[i], games.get(i).getTitle());
        System.out.println(games.get(i));
    }
 
    utx.commit();
}

In order for JPA to work, it needs a Persistence Unit. We define the Persistence Unit in the test-persistence.xml that’s associated with the target container.

ShrinkWrap takes this file from the classpath and puts it into its standard location within the archive.

.addManifestResource("test-persistence.xml", "persistence.xml")

Here’s the entire structure of the archive ShrinkWrap will assemble for this test case (minus the Arquillian infrastructure):

WEB-INF/
|-- beans.xml
|-- classes
|   |-- META-INF
|   |   `-- persistence.xml
|   `-- com
|       `-- acme
|           `-- jpa
|               |-- Game.class
|               |-- GamePersistenceTestCase.class
|               `-- Game_.class
`-- lib
    |-- ...

Let’s look at the Persistence Unit descriptor for Embedded GlassFish:

src/test/resources-glassfish-embedded/test-persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="test">
        <jta-data-source>jdbc/arquillian</jta-data-source>
        <properties>
            <property name="eclipselink.ddl-generation"
                value="drop-and-create-tables"/>
            <property name="eclipselink.logging.level" value="FINE"/>
        </properties>
    </persistence-unit>
</persistence>

We set two vendor-specific properties to activate features of the built-in provider, EclipseLink. The first property tells EclipseLink to generate the database to match the JPA entities. The second property enables logging of SQL statements so we can monitor the activity.

The Persistence Unit is referring to the JTA DataSource named jdbc/arquillian. Where’s that defined? Ah, that’s something the Arquillian container adapter needs to setup. As in Arun’s recipe, we want to use the GlassFish APIs to create a JDBC Connection Pool and associated Resource. But we don’t want to have to code it. We just want to declare it.

First, we create a sun-resources.xml file containing the resource definitions, which GlassFish knows how to consume.

src/test/resources-glassfish-embedded/sun-resources.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC
   -//Sun Microsystems, Inc.//DTD Application Server 9.0 Resource Definitions //EN
   http://www.sun.com/software/appserver/dtds/sun-resources_1_4.dtd>
<resources>
    <jdbc-resource pool-name="ArquillianEmbeddedDerbyPool"
        jndi-name="jdbc/arquillian"/>
    <jdbc-connection-pool name="ArquillianEmbeddedDerbyPool"
        res-type="javax.sql.DataSource"
        datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource"
        is-isolation-level-guaranteed="false">
        <property name="databaseName" value="target/databases/derby"/>
        <property name="createDatabase" value="create"/>
    </jdbc-connection-pool>
</resources>

We’ve now isolated the DataSource definition from the test in the same way we do in the main application. The further benefit is that we can define any resources we might need for our test. Imagine the possibilities.

Now we need to tell Arquillian to use this file. We open up the Arquillian configuration and configure the Embedded GlassFish container adapter to pick up this file, which it will feed to the asadmin add-resources command.

src/test/resources/arquillian.xml
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.com/arquillian"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:gfembed="urn:arq:org.jboss.arquillian.container.glassfish.embedded_3">
    <gfembed:container>
        <gfembed:sunResourcesXml>
            src/test/resources-glassfish-embedded/sun-resources.xml
        </gfembed:sunResourcesXml>
    </gfembed:container>
</arquillian>

All that’s left is to setup the Maven build to execute the test. To get this code to actually compile, we have to tell Maven it’s okay to use JDK 6 (it’s stubborn like that).

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.1</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
</build>

You also need to configure Maven to run the JPA 2 annotation processor, which I describe in another blog entry.

We’re going to separate out the target containers using Maven profiles. All of the profiles will share a common set of dependencies:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.1</version>
    </dependency>

    <dependency>
        <groupId>org.jboss.arquillian</groupId>
        <artifactId>arquillian-junit</artifactId>
        <version>1.0.0.Alpha4</version>
    </dependency>
</dependencies>

Here’s the profile for Embedded GlassFish. If you don’t want to target multiple containers, you can simply make this part of the top-level configuration.

<profile>
    <id>arq-glassfish-embedded</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-glassfish-embedded-3</artifactId>
            <version>1.0.0.Alpha4</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.extras</groupId>
            <artifactId>glassfish-embedded-all</artifactId>
            <version>3.0.1</version>
        </dependency>
    </dependencies>
    <build>
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
            </testResource>
            <testResource>
                <directory>src/test/resources-glassfish-embedded</directory>
            </testResource>
        </testResources>
    </build>
</profile>

We are explicitly adding the src/test/resources-glassfish-embedded directory as a test resource directory so that test-persistence.xml is placed into the classpath. Again, if you only intend on using Embedded GlassFish, this file can be moved into the standard Maven location and you can skip this configuration.

When you are done setting everything up, you can run the test with the following command:

$ mvn clean test

The profile for Embedded GlassFish is activated by default. Snippets of the test output is show below.

...
INFO: GlassFish Server Open Source Edition 3.0.1 (java_re-private)
...
Oct 4, 2010 1:01:56 PM org.jboss.arquillian.container.glassfish.embedded_3.GlassFishEmbeddedContainer executeCommand
INFO: add-resources command result (1): JDBC connection pool ArquillianEmbeddedDerbyPool created successfully.
Oct 4, 2010 1:01:56 PM org.jboss.arquillian.container.glassfish.embedded_3.GlassFishEmbeddedContainer executeCommand
INFO: add-resources command result (2): JDBC resource jdbc/arquillian created successfully.
Oct 4, 2010 1:01:56 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy$2$1 onReady
INFO: Grizzly Framework 1.9.18-o started in: 226ms listening on port 8181
...
Oct 4, 2010 1:07:14 PM com.sun.enterprise.web.WebApplication start
INFO: Loading application test at /test
...
Inserting records...
Selecting (using JPQL)...
Found 3 games (using JPQL)
Game@22609264[id = 1; title = Super Mario Brothers]
Game@3655662[id = 2; title = Mario Kart]
Game@20289248[id = 3; title = F-Zero]
Selecting (using Criteria)...
Found 3 games (using Criteria)
Game@25589884[id = 1; title = Super Mario Brothers]
Game@18616220[id = 2; title = Mario Kart]
Game@29940830[id = 3; title = F-Zero]
...
Oct 4, 2010 1:07:16 PM com.sun.enterprise.v3.server.AppServerStartup stop
INFO: Shutdown procedure finished

That’s a real integration test!

What’s more, we can run the exact same test on JBoss AS. We’ll need a different Persistence Unit definition that specifies a JDBC Resource available on JBoss AS and sets some Hibernate configuration settings. (Arquillian doesn’t yet support deploying a DataSource to JBoss AS—though it’s in the pipeline—so for now we use the built-in DataSource, java:/DefaultDS.).

src/test/resources-jbossas-remote/test-persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="test">
        <jta-data-source>java:/DefaultDS</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Then we need a Maven profile that adds the JBoss AS container adapter and client API libraries and the JBoss AS resources:

<profile>
    <id>arq-jbossas-managed</id>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-jbossas-managed-6</artifactId>
            <version>1.0.0.Alpha4</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.jbossas</groupId>
            <artifactId>jboss-as-client</artifactId>
            <version>6.0.0.20100721-M4</version>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <version>1.0.0.Beta7</version>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.jbossas</groupId>
            <artifactId>jboss-server-manager</artifactId>
            <version>1.0.3.GA</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
            </testResource>
            <testResource>
                <directory>src/test/resources-jbossas-remote</directory>
            </testResource>
        </testResources>
    </build>
</profile>

Now we run the test again using Maven, but this time activate the JBoss AS managed profile. (You need to set the JBOSS_HOME environment variable to point to a JBoss AS installation)

$ mvn clean test -Parq-jbossas-managed

Here’s the kicker. You can run this test into your IDE! Just import the project, open the test case and select “Run As > JUnit Test”. Voila! It works just like any other JUnit test.

Enjoy the perfect recipe for testing JPA!

While it may have seemed like a lot of preparation, recognize that we left no stone unturned. To remind you of the benefits, just look back at how simple the test case is. And remind yourself it’s not bound to any particular Java EE 6 container or JPA 2 implementation.

Stay tuned for other combinations, such as OpenEJB 3.2 Embedded with OpenJPA 2. So far I’ve figured out how to test JPA 1.x applications using OpenEJB 3.1 with OpenJPA, Hibernate and EclipseLink.

Arquillian 1.0.0 Alpha 1 Released!

I’m happy to announce the first alpha release of Arquillian, an open source (ASL v2) framework for running tests in the container. If you want to read more about Arquillian’s mission and how it fits into our vision for testing at JBoss, read Pete’s companion blog entry, Testing Java EE the JBoss way.

It’s one thing to unit test your code outside of the container, but what happens when you run it inside? Does it still behave the same? How about testing against container managed resources? This is where Arquillian comes into its own.

With Arquillian it’s just as easy to write integration tests as it is to write unit tests. In fact, to minimize the burden on you, Arquillian integrates with familiar testing frameworks, allowing reuse of tools such as the JUnit/TestNG support in your favorite IDE, Maven Surefire, Ant – in fact any tool which supports TestNG or JUnit!

To show you just how simple this is, here’s an example test case setup using JUnit (we’ll get to the actual test next):

@RunWith(org.jboss.arquillian.junit.Arquillian.class)
public class TemperatureConverterTestCase {
 
    @Deployment
    public static JavaArchive createTestArchive() {
        return Archives.create("test.jar", JavaArchive.class)
            .addClasses(TemperatureConverter.class, TemperatureConverterBean.class);
    }
 
}

By using JUnit’s @RunWith annotation, you tell JUnit to use Arquillian as the test controller. Arquillian will then look for a static method marked with the @Deployment annotation, which defines your micro-deployment. In the example above, the micro-deployment contains a session bean interface and implementation, which Arquillian will deploy to the container.

Arquillian hooks into your testing frameworks lifecycle and reacts to events. On the before suite and after suite events the container is started/stopped, while on the before class and after class events your micro-deployment is deployed to/undeployed from the container.

The test case is started in the local JVM. Arquillian then overrides the normal test execution and migrates the test so that it’s executed inside the container. By the time the test framework calls your @Test annotated method, the test is running inside the container, giving us the possibility to work with container managed resources. Here’s the complete test class with JUnit @Test methods.

@RunWith(org.jboss.arquillian.junit.Arquillian.class)
public class TemperatureConverterTestCase {
 
    @Deployment
    public static JavaArchive createTestArchive() {
        return Archives.create("test.jar", JavaArchive.class)
            .addClasses(TemperatureConverter.class, TemperatureConverterBean.class);
    }
 
    @EJB
    TemperatureConverter converter;
 
    @Test
    public void shouldConvertToCelsius() {
        Assert.assertEquals(converter.convertToCelsius(32d), 0d);
        Assert.assertEquals(converter.convertToCelsius(212d), 100d);
    }
 
    @Test
    public void shouldConvertToFarenheit() {
        Assert.assertEquals(converter.convertToFarenheit(0d), 32d);
        Assert.assertEquals(converter.convertToFarenheit(100d), 212d);
    }
}

Note how we can use @EJB to inject the session bean from our deployment into the test case for use in our test method – neat!

The Arquillian TestEnricher SPI supports all the injection annotations from Java EE 6:

  • @EJB
  • @Resource
  • @PersistenceContext
  • @Inject

Since there are no container specific code/configuration in this example test case, it’s portable. That means it can be run in GlassFish, JBoss AS or OpenEJB, or all three! The choice is yours.

I want to learn more, where should I go from here?

You can follow up with some in depth usage scenarios and tests described in these articles:

We also have reference documentation which walks you through the examples from Arquillian, and shows you how to create your own Arquillian test suite. You might also find the Javadoc useful (API, SPI), especially if you plan on adding support for another container. You can also check out the forums and more articles can be found on our community site. If your interested in chatting to us, please drop by #arquillian on irc.freenode.net

So, what’s next?

Some of the things you can expect from Arquillian in the future are:

  • Local run mode — Sometimes, you don’t want to run the test case inside the container itself. A local run mode will be added; a mode where your test controls the deployment but is not deployed as a part of it. This will give you the chance to run a test against, for example, JSF pages or RMI (testing for those nasty Non-Serializable / SessionClosed exceptions).
  • Multiple deployments controlled by same test — Sometimes your micro-deployment is not enough to test on its own and you want to package other components as part of the same deployment. For example, you need to test the interaction between two Web applications.
  • Support for method argument injection — In the first alpha we only support field injection. In alpha 2 we will be extending the TestEnricher SPI to include support for method argument injection:
@Test
public void shouldWithdrawFromAccount(@EJB AccountManager manager)
        throws Exception {
    ...
}
  • Test method interceptors – Another planned enricher SPI is a test method interceptor. With this we can add support for transactions:
@Test
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void shouldWithdrawFromAccount(@EJB AccountManager manager)
        throws Exception {
    ...
}
  • Convention over configuration – The micro-deployments should be as easy as possible to create, so adding support for common conventions should help speed up the test development. For example we can automatically add all classes in the same package as the test class to the deployment
  • Arquillian controlled resources – Sometimes the container requires container specific configuration e.g, java.naming.* parameters needed to create an InitialContext. If the test case has to explicitly deal with this, it places the burden for container portability back on the test case author. Arquillian will provide an extension point to add Arquillian created/managed resources:
// auto creation of InitialContext based on running container, remote or local.
@ArquillianResource
InitialContext context;
// auto creation of URL to a deployed Servlet, including http port/ip etc.
@ArquillianResource(MyServlet.class)
URL myServletURL;
// the bundle context of a deployed osgi bundle
@ArquillianResource
BundleContext context;
  • Support for more containers – We will plan to support more containers! Currently we have planned: GlassFish 3 (as a remote container), Jetty, Tomcat, Resin, Felix OSGI. (Hey Spring guys, you’re welcome to join in too!)
  • Third party integrations – In the spirit of ease of development, we integrate with existing test frameworks as much as possible, but we are always keen to learn of new frameworks we can integrate with. We already plan to support Selenium for example.
  • Support for other build tools – Arquillian Alpha1 comes with Maven support. In upcoming releases, we will distribute builds targeted toward other build tools like Ant and Gradle (that shout out is for our resident Gradle expert, Jason Porter).
  • A project page, logo and artwork – All good things must look good. That’s why the JBoss.org design team is hard at work putting together artwork for the Arquillian project page. Stay tuned!

Where can I see Arquillian in use?

Arquillian is a new framework, but it’s going to be put right to work as the workhorse to test all the Seam 3 modules. It will also be our recommended solution for testing your Seam application. (We’d love to see the community try it out for testing Seam 2 applications). We’ll also replace the current core of the JSR-299 CDI TCK with Arquillian, likely for the 1.1 version of the TCK. (To provide a little history, Arquillian originated from the JBoss Test Harness that was developed by Pete Muir as the foundation of the CDI TCK).

If you have any thoughts on these ideas, or would like to suggest some new avenues we should explore, please contact us on the Arquillian Dev forum.

And, what’s open source with out the community?!

A big thanks to the Arquillian and ShrinkWrap community for helping out on this release by being early adopters, joining in on community meetings, general discussions and writing blogs, articles and patches. In alphabetical order: Dan Allen, Steven Boscarine, German Escobar, Jordan Ganoff, Ken Gullaksen, Pete Muir, Jason Porter and Andrew Lee Rubinger. You guys rock!

[ Issues | Javadoc: API, SPI | Reference Guide | Release Notes | Maven artifacts ]

This post was syndicated from in.relation.to. See the original blog entry to view older comments.