Developer: J2EE

Out-of-Container EJB 3.0 Testing with Oracle Entity Test Harness
by Debu Panda

Learn how Oracle's Entity Test Harness makes it easier to practice Test-Driven Development with EJB 3.0 entity beans.

Published April 2006

Many software projects fail to deliver a high-quality product due to a lack of testing. Often, testing is either an afterthought or gets cut back when the project delivery schedule becomes tight. Furthermore, developers think they're responsible only for developing application modules and not for the overall quality of the application. As a result, they don't build test cases for the modules they create.

Test-Driven Development, a core practice of eXtreme Programming, revolutionized the development of object-oriented applications by making application testing a requirement, not an afterthought. It calls for developers to devise unit tests for each class they build. Many tools, utilities, and frameworks —such as JUnit and HttpUnit —are available to make this practice easier for Java developers, who have embraced Test-Driven Development over the last few years.

One of the main reasons Enterprise JavaBeans (EJB) has been shunned in recent years is because EJB components can't be easily unit tested. Fortunately, the EJB 3.0 spec greatly changes the programming model and promises to make EJB—primarily entities—usable and testable outside the container.

In this article, I will explain the benefits of Test-Driven Development and how EJB 3.0 promises to let you test EJB outside the container. I'll also propose how the Entity Test Harness provided with Oracle Application Server makes testing EJB 3.0 entities a reality.

Why Test-Driven Development?

Test-Driven Development improves software quality by requiring you to build unit tests before you develop a class. This approach offers the following benefits:

  • Tests become use cases and can validate the system design.
  • Application code becomes modular, so each module can be tested independently.
  • Automated unit tests are available when the application is ready for shipping.
  • Tests developed for the application can be treated as system documentation.
Test-Driven Development with EJB 2.x

EJBs are distributed components that are deployed and executed within an EJB container. Because EJBs require several resources provided by the J2EE server to perform their desired tasks, they can't be easily tested outside the container. Here are a few more reasons why such testing is difficult:

  • EJBs are not pure Java classes and they have lifecycle methods, so a runtime environment is a must.
  • EJB methods cannot be invoked directly and require JNDI to look up and create instances.
  • EJB requires services such as transactions and datasources for execution.

Unit testing Container Managed Persistence (CMP) entity beans is nevertheless difficult because CMP entity beans are abstract classes often front-ended with data transfer objects and session bean façadecmp s. The O-R mapping aspect of CMP entity beans is not standardized, so the entity bean gets tied to the deployment platform with mapping provided in a vendor-specific deployment descriptor.

Some developers have been using alternative approaches to automate EJB testing—such as in-container testing with Apache Cactus or out-of-container testing with lightweight frameworks—but their complexities have prevented widespread use.

In-Container EJB Testing

This approach involves deploying your EJB into an EJB container. As I mentioned previously, test frameworks such as Apache Cactus are available for testing EJB inside the container, but the main problem with this approach is that the tests become complicated and often dependent on the container APIs. Furthermore, if you change the code logic you must redeploy the EJB to the container, which is complex and time-consuming.

The main problems with running tests in the container are that you must create an entire deployment module and be able to configure and start the server—often involving other components and unrelated configuration and must packages—and deploy the application module.

Out-of-Container EJB Testing with Lightweight Frameworks

Frameworks such as MockEJB let you test EJBs outside the container. These frameworks, however, do not offer many options. They're not always up to date with EJB specifications and there are many other limitations. Session beans may be good candidates for outside-container testing with these frameworks, but testing entity beans is not always possible because of the complex services they provide. EJB 2.x entity beans are abstract classes and depend too much on the container for generating the persistence logic such as Container-Managed Relationship; thus, building such a framework is as complex as building another application server.

EJB 3.0 Simplification: The Promise for Developers

EJB 3.0 greatly simplifies the programming model. EJB now resembles a plain Java class often referred to as POJO (Plain Old Java Object) and the bean class now implements it as a business interface . The EJB classes do not have to implement java.ejb.EnterpriseBean interfaces; rather, the deployment descriptor is now optional for EJB and annotations are used instead.

EJB 3.0 also simplifies the API for CMP entity beans and standardizes on the POJO persistence model, similar to Oracle TopLink. Here are a few major changes in the persistence API that let you test entities outside the container with a lightweight framework:

  • Entities are now concrete classes and POJOs.
  • No interfaces are required for an entity bean, and Create, Read, Update, Delete (CRUD) operations are performed using EntityManager API.
  • O-R Mapping is now standardized and its dependencies on complex vendor descriptors are removed.
  • Container Managed Relationship is removed from the API.

Unit testing of entity beans has been a daunting task in the past. EJB 3.0 makes testing entity beans easier; because EJB 3.0 resembles a POJO, it's very easy to test these classes.

Entity beans are used for persistence and hence need access to the database and support for datasource objects. Support for JNDI is still required under EJB 3.0 because an instance of EntityManager needs to be grabbed for CRUD operation for entities. Transactions support is still needed because the EntityManager API must be invoked in a transactional context.

Oracle's Entity Test Harness

The Entity Test Harness in Oracle Application Server, a lightweight framework, makes testing entity beans outside the container simpler. It allows the same code that runs in the container to be used outside the container and doesn't require an Oracle-specific API.

The Oracle Application Server Entity Test Harness provides three essential services that are required to unit test entity beans:

  • Emulated DataSource
  • Base JNDI
  • Simple JTA functionality.
These services are extremely simplified; they're more emulated for testing than actual implementation required for deploying a production application.

The Oracle Application Server Entity Test Harness is packaged in a single jar file (ectest.jar) and depends on an EJB 3.0 persistence manager such as Oracle TopLink. It emulates the above three essential J2EE services to allow test code that uses these services to run outside the container. You can choose your test framework for testing entities using the Entity Test Harness and you don't have to use any Oracle-specific configuration.

When you use the Entity Test Harness to test your entities and the session bean façade, you don't need to make any changes to your application code.

To test your entities outside the container using the Entity Test Harness, you must perform the following steps:

1. Create the configuration class required by the Entity Test Harness. This configuration includes the datasource used by the application and the names of entities to be tested outside the container.

The EntityContainer class is the core of the Entity Test Harness. Applications don't have to instantiate this class; they are automatically instantiated by the test environment, so you can test the same entity bean. You must specify some essential configuration information for your container by returning a ContainerConfig instance from a static getContainerConfig() method. The configuration must include a JTA datasource name and a list of the entity beans to be tested. Optional attributes may include a session name and a non-JTA datasource name.

Here's an example that returns an instance of ContainerConfig:

package examples.ejb.cmp30.relationships;

import oracle.toplink.ejb3test.*;

import java.util.*;

public class OrderDemoSessionConfig  {

    public static DataSourceConfig getJtaDataSource() {
        return new DataSourceConfig(
            "DataSource", /* data source name */
            "jdbc/OracleDS", /* jndi name */
            "jdbc:oracle:thin:@localhost:1521:ORCL", /* URL */ 
            "oracle.jdbc.driver.OracleDriver", /* jdbc driver */
            "scott", /* user name */
            "tiger"); /* password */
    }

    
   public static Collection getEntities() {
        Vector classes = new Vector();
        classes.add("examples.ejb.cmp30.relationships.Customer");
        classes.add("examples.ejb.cmp30.relationships.Item");
        classes.add("examples.ejb.cmp30.relationships.Order");
        return classes;
    }

    public static ContainerConfig getContainerConfig() {
        return new ContainerConfig(
            null, /* session name */
            getJtaDataSource(), /* tx data source config */
            null, /* non-tx data source config */
            getEntities() /* entities */);
    }
}

The Entity Test Harness currently supports only one JTA and one non-JTA datasource.

2. Build your test class. Choose a test framework in which to build your unit test cases. These test classes do not require a container API.

In your test class, look up and grab an instance of EntityManager as follows:

Context ctx = new InitialContext();
           EntityManager em = (EntityManager) ctx.lookup("java:comp/ejb/EntityManager");

You can start a JTA transaction prior to using EntityManager API. You'll probably want to create a method in your test class that initializes the EntityManager and starts a UserTransaction. For example:

Context ctx = new InitialContext();
UserTransaction txn = (UserTransaction)    
                          ctx.lookup("java:comp/UserTransaction");
txn.begin();

3. Execute your test class with your desired framework. Here are few setup requirements for executing the tests.

  • The class that defines the container configuration must be specified as the value for a system property java.persistence.setup.config such as
    java -Djava.persistence.setup.config=examples.ejb.cmp30.relationships.OrderDemoSessionConfig
    
  • The ectest.jar file that contains the Entity Test Harness classes must be in the CLASSPATH and the JVM must start with the -javaagent option.
  • For example, if you've built a test class named MyTest with a configuration class OrderDemoSessionConfig, then you must execute your test case as follows:

    java 
    -Djava.persistence.setup.config="examples.ejb.cmp30.relationships.OrderDemoSessionConfig" 
    -javaagent:d:/myhome/toplink/jlib/ectest.jar MyTest
    
Next Steps

1. Download Oracle Application Server 10g (10.1.3)

2. Read Preparing for EJB 3.0

3. Test EJB 3.0 Entities Outside Container: Example Code

4. Download more EJB 3.0 Samples (zip)

Related Resources:

Getting started with EJB 3.0

In-Container Testing with JUnit

You can build your test cases with frameworks such as JUnit or JTestCase.

Testability of Session Beans

Oracle's Entity Test Harness also lets you test session bean façades for entity beans. A session bean is a simple Java class that implements its business interface, annotates its type, and can be easily unit tested outside the container via a test framework. The complexity occurs when it uses JNDI lookup or dependency injection to use any resources or services. It's also difficult to test the functionality of session beans that are used only as façades for the entity beans without a test harness that supports entity beans.

Summary

EJB 3.0 simplifies the programming model, enabling you to test EJBs outside the container. The Entity Test Harness provided with Oracle Application Server makes it easier to practice Test-Driven Development with EJB 3.0 entity beans, and lets you start testing EJB 3.0 entity beans outside the container right now.


Debu Panda is a principal product manager of the Oracle Application Server development team, where he focuses his efforts on the EJB container and Transaction Manager. He has more than 13 years of experience in the IT industry, has published articles in several magazines, and has presented at many conferences. His can be reached through his J2EE-focused weblog .


Send us your comments