Integration tests with Arquillian on WebLogic 12

Posted by nerdcoding on April 13, 2015

In this tutorial we will implement a simple JavaEE 7 application with a single JPA entity and a EJB which uses that entity. We will write an integration test for this EJB which is executed with Arquillian and runs on a WebLogic application server. You can skip the long (and hopefully not too boring) explanation and directly clone a fully working example from https://github.com/nerdcoding/arquillian-on-weblogic.

What is Arquillian? Why should I use it?

In JavaEE everything is about managed beans. A managed bean is first and foremost a simple Java class whose instances are created and managed by an application server. Managed beans are also called server side components. JavaEE defines different managed beans for different purposes. The most used are JSF managed beans, CDI beans and EJBs.

A managed bean is something that lives inside of a server and a lot of it’s functionality is provided by this server. For example a method call on an EJB is by default transactional and the server takes care of this transactional behavior. But what is when you want to write a JUnit test for your EJBs. A JUnit test is something that runs locally and not on a application server. So all the server provided functionality aren’t available. In most cases you want to run a JUnit test for an EJB within realistic constraints. You want to run your a JUnit test for an EJB on an application server so it is a real test that tests the EJB exactly under the same conditions as it would run in production.

That is where Arquillian comes into play. With Arquillian you can write a simple JUnit test for an EJB and when you run this test locally, Arquillian deployes the EJB on a application server and executes the test for this EJB.

In the following I will show you how to write JUnit tests based on Arquillian and how to configure them to run on Oracles WebLogic application server.

One more word about the terms. When a test runs with Arquillian this is a "integration test" and not a "unit test" (although when we use JUnit). This is because of our test runs inside of a container and so is "integrated" in a real life environment. You can read more about the difference between integration and unit tests at stackoverflow.

Install WebLogic application server

As prerequisite to run Arquillian tests on the WebLogic you need to have a installed WebLogic Server at your disposal. If you currently don’t have access to a WebLogic server, don’t worry. It is surprisingly easy to install it at your local machine. The fastest way to install a WebLogic is to download the "Zip distribution for Mac OSX, Windows, and Linux" at WebLogic Server Downloads. For development purposes Oracles WebLogic server is free to use. You only need to register for an free Oracle account. For a detailed installation description you could study the WebLogic documentation or have a look at this readme (Oracle login required) which is absolutely sufficient for a basic installation.

In the following I will use WebLogic server in the version 12.1.3 and assume that the WebLogic domain is installed at DOMAIN_HOME. Pleas keep in mind that any previous WebLogic version does not support JavaEE 7. But that shouldn’t matter because no specific JavaEE 7 features are used at this tutorial.

Database and data source

An integration test based on Arquillian is a test for a real life application. For this purpose we need a running database and configure a WebLogic data source for this database. Download the H2 database unzip the archive and start the database with:

java -jar bin/h2-1.4.186.jar -tcp -tcpAllowOthers -web -webAllowOthers

Maybe you need to adjust the H2 version number. That is anything we need to do for a running database! Now we want to configure a data source for this database. First copy the h2-1.4.186.jar into your WebLogic domain in DOMAIN_HOME/libs. Than start the WebLogic server by it’s start script DOMAIN_HOME/startWebLogic.sh open your browser and use the "WebLogic Server Administration Console" at http://127.0.0.1:7001/console/. During the domain creation process when WebLogic was installed, you must have defined a domain user. With this credentials you can login administration console.

With Services → Data Sources → New an new Generic Data Source could be created.

Name: AOW Data Source
JNDI Name: jdbc/aow
Database Type: Other
"Supports Global Transactions"
"One-Phase Commit"
Database User Name: sa
Password stays empty
Driver Class Name: org.h2.Driver
URL: jdbc:h2:tcp://localhost/~/aow
Select Targets -> Servers: check "myserver"

Required dependencies

There are some dependencies which needs to be defined in our pom.xml. When we develop a JavaEE application obviously the JavaEE API is needed. Anymore some test dependencies are needed. Except from JUnit and the Arquillian dependencies we need arquillian-wls-remote to deploy our test artifacts on a WebLogic server and we use the arquillian-persistence-impl for transactional behavior in our test classes.

pom.xml
<dependencyManagement>
   <dependencies>
      <dependency>
         <groupId>org.jboss.arquillian</groupId>
         <artifactId>arquillian-bom</artifactId>
         <version>1.1.7.Final</version>
         <scope>import</scope>
         <type>pom</type>
      </dependency>
   </dependencies>
</dependencyManagement>

<dependencies>
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
   </dependency>

   <dependency>
      <groupId>org.jboss.arquillian.junit</groupId>
      <artifactId>arquillian-junit-container</artifactId>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>org.jboss.arquillian.extension</groupId>
      <artifactId>arquillian-persistence-impl</artifactId>
      <version>1.0.0.Alpha6</version>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>org.jboss.arquillian.container</groupId>
      <artifactId>arquillian-wls-remote-12.1</artifactId>
      <version>1.0.0.Alpha3</version>
      <scope>test</scope>
   </dependency>

   <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
   </dependency>
</dependencies>

A small JavaEE application

The application itself consist of a small JPA entity and a EJB which creates and saves instances of this entity. Anymore the EJB defines a very simple JPQL query.

Person.java
package org.nerdcoding.sample.arquillian.weblogic.jpa;

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String firstName;

    private String lastName;

    @Temporal(TemporalType.DATE)
    private Date dayOfBirth;

    // getter and setter
}
PersonService.java
package org.nerdcoding.sample.arquillian.weblogic.ejb;

@Stateless
public class PersonService {

    @PersistenceContext
    private EntityManager entityManager;

    public Person createPerson(final String firstName, final String lastName,
			       final Date dayOfBirth) {
        final Person person = new Person();
        person.setFirstName(firstName);
        person.setLastName(lastName);
        person.setDayOfBirth(dayOfBirth);

        entityManager.persist(person);

        return person;
    }

    public List<Person> findByLastName(final String lastName) {
        TypedQuery<Person> query = entityManager.createQuery(
		   "select p from Person p where p.lastName = :lastName", Person.class);
        query.setParameter("lastName", lastName);

        return query.getResultList();
    }
}

Lastly we create a persistence.xml to connect our previously configured data source with this application.

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="aow" transaction-type="JTA">
        <jta-data-source>jdbc/aow</jta-data-source>
        <properties>
            <property name="javax.persistence.schema-generation.database.action"
		      value="create"/>
            <property name="eclipselink.deploy-on-startup" value="true"/>
        </properties>
    </persistence-unit>

</persistence>

Use Arquillian to test that EJB

Now we want to write a test for our just created EJB and we use Arquillian to deploy that EJB to a WebLogic server during the test execution and test the EJB in a real environment.

Define deployment artifact

First we need to tell Arquillian what should be deployed during the test execution. We implement an abstract class which contains the logic to create a WAR archive before test execution. This WAR archive contains our application and could be deployed on the WebLogic server. Arquillian will automatically create this WAR and deploys it before each test.

AbstractArquillianIT
@RunWith(Arquillian.class) (1)
@Transactional(TransactionMode.ROLLBACK) (2)
public abstract class AbstractArquillianIT {

    private static final String DEPLOYMENT_PACKAGE = "org.nerdcoding.sample.arquillian.weblogic";

    @Deployment
    public static WebArchive createDeployment() throws Exception {
        return ShrinkWrap.create(WebArchive.class, "test.war")  (3)
                .addPackages(true, DEPLOYMENT_PACKAGE) (4)
                .addAsResource("META-INF/test-persistence.xml",
			"META-INF/persistence.xml"); (5)
    }

}
  1. Here we use Arquillians JUnit runner so the JUnit test are executed by Arquillian and not by JUnit itself.

  2. Arquillians persistence extension is used here. For each test method a new transaction is started and we rollback the transaction. So all tests are independent of another because there are never stale data in the test database.

  3. Before each test Arquillian deploys the application which should be tested. Here we create programmatically the WAR file.

  4. Arquillian needs to know what classes should be packaged in the WAR archive. We specify that anything form the java package (and recursively from sub packages) should be part of the WAR.

  5. In src/test/resources/META-INF we create a test-persistence.xml which should be part of the test WAR. In our example this test-persistence.xml is identical as the persistence.xml we created previously in our application. But normally the application and the tests should use different data sources, so here we have to possibility to define a different data source only for tests.

Arquillian configuration

In order to the deploy our programmatically created WAR to the WebLogic server, Arquillian has to know where to find the locally installed WebLogic.

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

   <container qualifier="wls-local" default="true">
      <configuration>
         <property name="adminUrl">t3://localhost:7001</property> (1)
         <property name="adminUserName">admin</property> (2)
         <property name="adminPassword">admin123</property>
         <property name="target">myserver</property> (3)
         <property name="wlHome">/tmp/wls12130/wlserver/</property> (4)
      </configuration>
   </container>
</arquillian>
  1. Host and port where the WebLogic server is running.

  2. Credentials defined during domain creation when WebLogic was installed.

  3. A WebLogic server could have more than one running instances. Here the server instance is defined, which would be used by Arquillian. In the WebLogic administration console (see [Database and data source] you could find the name of your server instance under Environment → Servers

  4. The path to your WebLogic installation.

In this example we use arquillian-wls-remote. That means the WebLogic server needs to be started and running before a test is executed. With arquillian-wls-managed it is also possible the run test on a WebLogic server which was not started. In this case Arquillian handles the starting and stopping of the server by itself (see also https://github.com/arquillian/arquillian-container-wls).

Implement test class

Now we could write a simple JUnit for our PersonService EJB.

PersonServiceIT
public class PersonServiceIT extends AbstractArquillianIT { (1)

    @EJB (2)
    private PersonService personService;

    @Test
    public void testCreatePerson() { (3)
        Person person = personService.createPerson("Sheldon", "Cooper", new Date());
        assertNotNull(person);
        assertNotNull(person.getId());
    }


    @Test
    public void testFindByLastName() { (4)
        personService.createPerson("Johnny", "Cooper", new Date());
        personService.createPerson("Alice", "Cooper", new Date());
        personService.createPerson("Milhouse", "Van Houten", new Date());
        personService.createPerson("Luke", "Skywalker", new Date());

        List<Person> found = personService.findByLastName("Cooper");
        assertEquals(2, found.size());

        found = personService.findByLastName("Skywalker");
        assertEquals(1, found.size());
    }

}
  1. Extend form the previously created abstract class so the tests runs with Arquillian.

  2. Arquillian treats our test class as a normal managed bean. So yes, dependency injection just works in our test classes.

  3. Test the EJBs createPerson() method and checks if a person was created and persisted to database.

  4. Here we test the EJBs findByLstName() method. A few persons are created, saved and then the finder loads this persons. Note: we created two persons named "Cooper" in this test and we found two persons in the database. The "Cooper" from the testCreatePerson() does not exists in the database anymore. Remember in the AbstractArquillianIT we configured that the transaction of each test method should to a rollback at the end. So both test methods are really independent of each other. Change the annotation in AbstractArquillianIT to @Transactional(TransactionMode.COMMIT). Then the testFindByLastName() would fail because it found three persons named "Cooper".

To execute the test in my IntelliJ IDEA I only need to run the PersonServiceIT class as a normal JUnit test (make sure the WebLogic server is running). And I’m pretty sure it will also work in Netbeans or Eclipse.