Simple EJB Arquillian test based on JUnit running on managed JBoss AS 7

I believe that every programmer understands the need for testing. We want our code to be tested and bug free, but the time is of the essence. We need tests to be easily written and executed and as exact as possible.
From my experience, testing Java EE always required a special treatment. You could either code additional means to enable launching tests from your application, or you were left with creating a test environment using for example OpenEJB for beans, something different for transactions and something else for persistence. The second approach is better, because it is more manageable and transparent, but it's downside is that the tests are run in a different environment than the one used as runtime. This means that not everything that works in tests will work when deployed on server and vice versa.

In this post I am demonstrating the power of Arquillian.

This framework enables us to run the tests easily in the runtime container our application needs. My example uses managed Jboss AS 7, but there are other possibilities.

I spend a lot of time trying to make Arquillian work in my project and now I can definitely say that it is not the way you want to start with Arquillian. The configuration is not tricky or that difficult, but you do not want to deal with more problems than necessary. That is why I am recommending you to create a new Maven project and begin exploring the Arquillian's possibilities from the simplest setup.

First goal

My first goal wast to have one EJB with one test running on JBoss AS 7. Although I personally prefer TestNG over JUnit, this example uses JUnit because Arquillian's Getting Started guide uses it. I will demonstrate usage of TestNG on a more complex example in my next post.

Step by Step

  1. Create a Maven project
  2. Setup pom.xml to support the testing
  3. Create the EJB class
  4. Create the test class
  5. Setup arquillian.xml

 

Create a Maven project

I recommend creating a special project for the tests, because there are a lot of dependencies needed for testing, but superfluous in the rest of your application.

 

Setup pom.xml

Here is my version of pom.xml. The most important parts are arquillian bom dependency management and arq-jbossas-managed profile. Dependency in dependency management org.jboss.arquillian:arquillian-bom:1.1.0.Final contains all the essential libraries needed for the launching the test. The arq-jbossas-managed profile is responsible for executing the tests.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>cz.effy.server</groupId>
 <artifactId>junit.test</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>test</name>
 <properties>
  <version.junit>4.8.2</version.junit>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.jboss.spec.javax.ejb</groupId>
   <artifactId>jboss-ejb-api_3.1_spec</artifactId>
   <version>1.0.1.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.enterprise</groupId>
   <artifactId>cdi-api</artifactId>
   <version>1.0-SP4</version>
   <scope>provided</scope>
   <exclusions>
    <exclusion>
     <artifactId>jboss-interceptor-api</artifactId>
     <groupId>org.jboss.interceptor</groupId>
    </exclusion>
    <exclusion>
     <artifactId>jsr250-api</artifactId>
     <groupId>javax.annotation</groupId>
    </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>${version.junit}</version>
  </dependency>
  <dependency>
   <groupId>org.jboss.arquillian.junit</groupId>
   <artifactId>arquillian-junit-container</artifactId>
  </dependency>
  <dependency>
   <groupId>org.jboss.arquillian.protocol</groupId>
   <artifactId>arquillian-protocol-servlet</artifactId>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <dependencyManagement>
  <dependencies>
   <dependency>
    <groupId>org.jboss.arquillian</groupId>
    <artifactId>arquillian-bom</artifactId>
    <version>1.1.0.Final</version>
    <scope>import</scope>
    <type>pom</type>
   </dependency>
  </dependencies>
 </dependencyManagement>
 <build>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
     <encoding>UTF-8</encoding>
     <source>1.7</source>
     <target>1.7</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <profiles>
  <profile>
   <!-- An optional Arquillian testing profile that executes tests in your 
    JBoss AS instance -->
   <!-- This profile will start a new JBoss AS instance, and execute the 
    test, shutting it down when done -->
   <id>arq-jbossas-managed</id>
   <activation>
    <activeByDefault>true</activeByDefault>
   </activation>
   <dependencies>
    <dependency>
     <groupId>org.jboss.as</groupId>
     <artifactId>jboss-as-arquillian-container-managed</artifactId>
     <version>7.1.1.Final</version>
     <scope>test</scope>
    </dependency>
   </dependencies>
  </profile>
 </profiles>
</project>

Create the EJB

I used the simplest enterprise bean I could think of ... Singleton.
package cz.effy.server.testng.test;

import javax.ejb.Singleton;

@Singleton
public class HelloBean {

 public String getHello() {
  return "Hi!";
 }

}

Test class

The test is a bit different from a regular unit test although the test method looks exactly as expected. The first thing you will probably notice is the @RunWith annotation that specifies the Arquilllian as the test runner. The second difference is the presence of a @Deployment annotated method. This method creates an archive to be tested. You need tu put all the essential classes into it, but the test class itself does not belong in it.
package cz.effy.server.testng.test;

import javax.inject.Inject;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class HelloBeanTest {

 @Inject
 private HelloBean hello;

 @Deployment
 public static JavaArchive createTestArchive() {
  return ShrinkWrap.create(JavaArchive.class, "helloEJB.jar")
    .addClasses(HelloBean.class)
    // tested EJB
    .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    // enabling CDI
 }

 @Test
 public void testHelloEJB() {
  String result = hello.getHello();
  Assert.assertEquals("Hi!", result);
 }
}

Setup arquillian.xml

This file contains a configuration for the arquillian container. And as was previously indicated ... this one deals with managed JBoss AS 7. You need to replace the jbossHome property with a value for your environment. Windows path looks like this C:\servers\jboss-as-7.1.1.Final.
<?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">
   <!-- Uncomment to have test archives exported to the file system for inspection -->
<!--    <engine>  -->
<!--       <property name="deploymentExportPath">target/</property>  -->
<!--    </engine> -->

   <!-- Force the use of the Servlet 3.0 protocol with all containers, as it is the most mature --> 
   <defaultProtocol type="Servlet 3.0" /> 

   <!-- Example configuration for a remote JBoss AS 7 instance -->
   <container qualifier="jboss" default="true">
      <!-- If you want to use the JBOSS_HOME environment variable, just delete the jbossHome property -->
      <configuration>
         <property name="jbossHome">/home/petr/servers/jboss-as-7.1.1.Final</property>
      </configuration>
   </container>
</arquillian>

Executing the test

You can run the test exactly as any other JUnit test, the added libraries will take care of the rest. Just keep in mind that the JBoss AS 7 will be launched in standalone configuration thus everything located in the deployments folder will be deployed, possibly slowing the tests.

Conclusion

The configuration might be a little complicated at first, but the result is highly rewarding. This simple test takes only 10+ seconds to execute and that is not bad in my opinion as the container only starts once per run.
I tried to keep this post simple, but it definitely got longer than planned. I do hope that it will prove useful.
I got really exited about all the possibilities arquillian offers. I plan to use arquillian for testing purposes on project right away.

Comments

Popular posts from this blog

Automatic jsp recompile on Jboss AS 7

Password hashing in Java

Running scripts written in Clojure as an executable using Inlein