alt
November 12th, 2010

by Ivan St. Ivanov

In this three part series I am going to show you how you can easily test classes that are managed by the various containers in the Java world. In the first part we developed a Spring managed service which we tested using the Spring test context framework. Today we are going to dig into the Java EE realm. We will create a session EJB which we’ll test with the help of the Glassfish embedded container.

Java EE 6 quick review

Before going into the details of our sample scenario, let’s take a quick look at the environment that we are going to develop in.

Versions 5 and especially 6 of the Java EE specification simplified very much developer’s life by bringing the best practices from other Java enterprise frameworks like Spring and Hibernate.  EJB 3.1, which is part of Java EE 6 improves developer’s experience compared to EJB 2.1 “famous” with its deployment descriptors, home and remote interfaces, container-managed persistence, etc. Now every piece of configuration is optional and can be done both via XML or annotations. There are sensible defaults for nearly everything. Now it’s so easy to make use of dependency and resource injection, transactions and security. However, looking at all the details of Java EE is beyond the scope of this article. There are plenty of resources on the web and also some quite useful books.

One of the newly introduced features of the specification is the so called embedded EJB container. Each Java EE 6 compliant server should provide an embeddable implementation of the EJB container. This implementation can be controlled, i.e. started and stopped, from virtually any class, without the need for the latter to be deployed on the server. This is very useful for unit tests. They just have to start the container and lookup from there all the beans available in the project classpath. No more need for complex mocking frameworks or heavy environment preparation upfront each test.

Before we see the embedded container in action, let’s first

Set the project up

The development environment and the usecase are the same as in the first part of the series. We setup the project using nearly the same maven command:

mvn archetype:create -DgroupId=com.foo -DartifactId=my-bar-javaee -DarchetypeArtifactId=maven-archetype-webapp

And we again add these in the pom.xml in order to enable Java 6 and to include the JUnit dependency:

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

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <inherited>true</inherited>
      <configuration>
        <source>1.6</source>
        <target>1.6</target>
      </configuration>
    </plugin>
  </plugins>
</build>

The persistence

In the pre-Java EE 5 days in order to persistence something in the database you needed to develop an entity EJB with all the interfaces, deployment descriptors, EJBQL, etc. This assured scalability and consistency, but was very hard to develop. And was proprietary solution to the Java EE world. With the advent of Hibernate the so called Object relation mapping (ORM) solutions gained pace to arrive at the current state, where the Java persistence API (JPA) is the standard for mapping the object oriented structure of the domain to the relational nature of the databases.

What is good about JPA is that it evolves in its own JSR and can be used both inside and outside of the Java EE compliant servers. What you only need is a JPA provider library. Remember, this is what we did in the first part of the series, where we could configure the Spring framework to inject an implementation of JPA’s entity manager interface into our bean. What we had to do in addition was to initialize our entity manager factory in the Spring configuration file.

In the Java EE world we configure our entity classes in absolutely the same way as in Spring:

@Entity
@NamedQuery(name = "findAllTeamsByCountry", query = "select t from Team t where t.country = :country")
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    private String city;
    private String stadium;
    private String country;
...
// Getters and setters skipped for clarity
}

However the persistence.xml is slightly different:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
  <persistence-unit name="barPU">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/__default</jta-data-source>
    <class>com.foo.Team</class>
    <properties>
      <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
      <property name="eclipselink.logging.level" value="INFO" />
    </properties>
  </persistence-unit>
</persistence>

We stated here that the persistence provider is EclipseLink. This is the reference implementation of the JPA specification and comes with the Glassfish application server. We also declare a JTA data source tag. This tells the JPA provider that the server container will take care for starting and stopping the entity manager transactions. The value there should map to an existing data source created in the application server. You’ll see later how this is achieved in the embedded container.

The persistence provider vendor specific configuration is usually also put in persistence.xml (we had it in the application context XML in the Spring solution).

As mentioned earlier, the JPA provider is part of the Glassfish server, so we don’t have to include an explicit dependency to it in our pom.xml. The only thing that we should declare there in order for our entity to compile is:

<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>persistence-api</artifactId>
  <version>1.0</version>
  <type>jar</type>
  <scope>provided</scope>
</dependency>

We don’t need to package this jar as the server has it bundled. That is why the scope is set to provided.

Implementing the session bean

In Java EE 6 the reusable services are usually implemented as session beans. This is another area of the Java EE world, which was very simplified in the last version of the specification. I will not go into much details here as this is not the topic of the current posting (wow, I haven’t even thought of starting to write about testing yet :-)).

Our stateless session bean (which is a pure Data access object) looks very similar to the Spring bean:

@Stateless
public class TeamEjb {

    @PersistenceContext(unitName = "barPU")
    private EntityManager em;

    public Team createTeam(Team team) {
        em.persist(team);
        return team;
    }

    @SuppressWarnings("unchecked")
    public List<Team> findAllTeamsFromCountry(String country) {
        Query query = em.createNamedQuery("findAllTeamsByCountry");
        query.setParameter("country", country);
        return query.getResultList();
    }
}

By annotating the service with @Stateless you tell the EJB container to treat this as stateless session bean and provide all the services and infrastructure to it: transactional behavior, resource injection, automatic lifecycle management, etc. As of EJB 3.1 it is not mandatory that a sessions bean implements an interface.

As in the Spring example the entity manager is injected (using the same annotation to mark it). The business methods (createTeam, findAllTeamsFromCountry) are transactional by default, so there is no need for additional annotations to them.

The only thing that we have to do for our session bean is to add the EJB dependency in the pom.xml (again with provided scope):

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.ejb</artifactId>
    <version>3.0</version>
    <scope>provided</scope>
</dependency>

We’ll also need to configure the path to the Glassfish maven repository, as the default repository does not contain the above library (and also some of the jars that we’ll need later):

<repositories>
  <repository>
    <id>Glassfish</id>
    <name>Glassfish Repository</name>
    <url>http://download.java.net/maven/glassfish</url>
  </repository>
</repositories>

Testing with Embedded Glassfish

As already mentioned each Java EE compliant server should provide an embedded EJB container implementation. This implementation behaves exactly as real EJB container and the classes that use it can lookup from there the “deployed” beans. You don’t necessarily need to deploy anything explicitly in this container, but you can expect that every bean class in the classpath can be discovered in a specified way.

This container does not appear in our code from nowhere though. You need to have somewhere in your project the file domains/domain1/config/domain.xml. What you can easily do is take this file from an existing Glassvish v3 clean installation and put it under your project’s resource directory. I prefer to place this directory tree under <project-dir>/src/test/resources/glassfish.After obtaining this file, we need to start configuring it in order to fit for our test suites’ needs. So, let’s begin!

As we are going to use a database in our particular test, we need to configure our data source and expose it to JNDI. In the first part of the series we used the in-memory HSQLDB and this time we’ll again stick to it rather than using the default Apache Derby. Usually the steps below are done with the asadmin command line interface or through the Web admin program, but we are going to hack everything manually inside the configuration file.

So, remove everything inside the resources tag. Then add jdbc-connection-pool element with the following sample content:

<resources>
  <jdbc-connection-pool is-isolation-level-guaranteed="false" name="HsqldbPool" driver-classname="org.hsqldb.jdbcDriver"
   res-type="java.sql.Driver">
    <property value="9001" name="PortNumber" />
    <property value="" name="Password" />
    <property value="sa" name="User" />
    <property value="localhost" name="serverName" />
    <property value="jdbc:hsqldb:mem:foobar" name="URL" />
  </jdbc-connection-pool>
</resources>

This creates a pool of java.sql.Driver objects (I couldn’t make it work with pool of data sources). This pool’s name is HsqldbPool. Next we need to expose this pool in JNDI so that our entity manager implementation can find it. Again inside the same resources tag include this:

<resources>
  ...
  <jdbc-resource pool-name="HsqldbPool" jndi-name="jdbc/__default" />
</resources>

Now we have the HsqldbPool exposed to JNDI under the jdbc/__default path. Remember that this is the data source that we declared earlier in our JPA persistence.xml:

    <jta-data-source>jdbc/__default</jta-data-source>

We should now add the above resource to our server configuration. Add this tag under the resources element:

<servers>
  <server name="server" config-ref="server-config">
    <resource-ref ref="jdbc/__default" />
  </server>
</servers>

That’s all the hacking for now. You may download the source code of this project and see under its src/test/resources/glassfish directory the whole Glassfish server configuration that I used for my test.

Now that we prepared our server environment we are ready to start it up. In order to do so we can use EJBContainer’s createEJBContainer static method. We need to tell this method where to look for its configuration. The best place to do that is in our unit test’s @BeforeClass method. We will also initialize a Context variable that we’ll later use to lookup our session bean:

public class TeamEjbTest {

    private static EJBContainer container;
    private static Context ctx;

    @BeforeClass
    public static void setup() {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("org.glassfish.ejb.embedded.glassfish.installation.root",
            "./src/test/resources/glassfish");
        container = EJBContainer.createEJBContainer(properties);
        ctx = container.getContext();
    }

    ...
}

The above code will start the container, which will eventually initialize the DB resources that we configured before.

Now it’s time to test. As our unit test is running outside the container we cannot inject directly the Team EJB. We have to look it up. However, this does not mean that our bean has to implement a remote interface. It actually does not need to implement any interface and still can be looked up by our unit test. The Java EE specification has defined a standard path to find EJBs in server’s context: java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>]. However, we don’t want to package and deploy our bean just for the sake of unit testing it. So we’ll use a slightly different lookup path:

TeamEjb teamEjb = (TeamEjb) ctx.lookup("java:global/classes/TeamEjb");

This will attempt finding our bean named TeamEjb in the directory with our compiled classes. Now that we know how to get our bean from the server context we can finally proceed to the real test:

@Test
public void testTeamService() throws NamingException {
    Team testTeam = new Team();
    testTeam.setName("CSKA");
    testTeam.setCity("Sofia");
    testTeam.setCountry("Bulgaria");
    testTeam.setStadium("Bulgarska armiya");

    TeamEjb teamEjb = (TeamEjb) ctx
        .lookup("java:global/classes/TeamEjb");

    teamEjb.createTeam(testTeam);

    assertEquals(1, teamEjb.findAllTeamsFromCountry("Bulgaria").size());
}

That’s it!

Of course, let’s not forget about the additional dependencies that we’ll need for our test to compile and run. Add these to the pom.xml:

<dependency>
  <groupId>org.hsqldb</groupId>
  <artifactId>hsqldb</artifactId>
  <version>2.0.0</version>
  <type>jar</type>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.glassfish.extras</groupId>
  <artifactId>glassfish-embedded-all</artifactId>
  <version>3.0</version>
  <scope>test</scope>
</dependency>

The glassfish-embedded-all jar is quite big, so be patient the first time you run the build.

Of course, it is good practice to cleanup the resources when the tests are over, so don’t forget this:

@AfterClass
public static void teardown() {
    container.close();
}

Conclusion

In the second part of our series on unit testing we took a look how you can develop session EJBs and use the Glassfish embedded container to test them. We didn’t need to build and deploy our bean and could easily configure the container to find it amongst the classes in the classpath. We also saw how to configure an HSQLDB data source (actually DB driver) to be used by our Glassfish container.

In the final part of the series we’ll test exactly the same EJB, but this time using JBoss’s Arquillian library.

Resources

You can download the source code of the above sample from here.

3 Responses to “ Unit testing services, part 2 – Embedded Glassfish ”

  1. Rob Weaver says:

    Thanks, this was very helpful – was having all sorts of issues with getting my project set up on Maven until I found your article and inspected your project.

  2. ivko3 says:

    Hi Rob!

    Great that this old post was helpful.

    But you may check Arquillian for integration testing. It’s already Final and is great!

    Cheers,
    Ivan

  3. Applicius says:

    About JDBC/persistence unit testing, opensource Acolyte framework has been recently developed, and is working with API like JPA, entities, Anorm… http://applicius-en.tumblr.com/post/55081625831/persistence-unit-test

Leave a Reply


× six = 24