Streamlining Your EJB Tests With MockEJB
Pages: 1, 2, 3, 4

Introducing MockEJB

MockEJB is an EJB testing framework written by Alexander Ananiev. It combines a number of existing ideas and technologies that give the EJB developer a powerful testing framework for easy unit testing of EJBs, both inside and outside the EJB container. In essence, MockEJB provides mock object implementations of all the important J2EE interfaces required by an EJB and therefore provides a mock container implementation that developers can easily control from their unit tests. The mock container it provides is a plain Java object and allows EJBs to be tested as plain Java objects, outside the traditional container of a J2EE application server. However, MockEJB also integrates with the Cactus server-side testing framework and provides the EJB developer with a unit test environment inside the application server, if required.

This article focuses on the use of MockEJB for testing beans outside the application server. When used in this way, some of the key features that MockEJB provides include:

  • Automatic generation of the EJBObject implementing your interfaces, calling your bean class.
  • Provision of the bean environment, including container transactions, EJBContext objects, and EJBMetaData.
  • An in-memory JNDI provider, allowing the binding and lookup of container resources.
  • Invocation of operations on other EJBs.
  • Support for CMP and BMP entity beans.
  • An in-memory JMS provider, allowing JMS messages to be sent and received.
  • The ability to add interceptors around the bean to allow control and monitoring of the test environment.

MockEJB is supplied as a Java library, with samples and javadoc documentation to guide its use. Like most libraries, the easiest way to come to grips with MockEJB is to use it to solve some simple problems, and so in the next section, we'll see how MockEJB can help you test some session beans.

Using MockEJB

To illustrate the use of MockEJB, we have developed a very simple application containing two session beans and one MDB. The zip file associated with this article contains a simple codeline comprising the source code for the beans under test, the unit test source code, and an Ant build script to build and test the beans. To build the code and run the tests, you will need to install Ant, JUnit, and MockEJB, as well as the JDK. You can get full instructions for using the example code in the README file within the codeline.

The EJBs provided have been developed to allow you to investigate some specific features of MockEJB, and are all extremely simple, providing a basic calculator via various service interfaces. Three beans are included:

  • SimpleCalc is the simplest bean, a stateless session bean offering a remote interface providing addition, subtraction, multiplication, and division services for double operands. This bean allows you to investigate MockEJB's support for simple EJB testing.
  • ParsingCalc is another stateless session bean that offers a single calculate(String expression) operation. This bean parses the string expression passed to it to extract the operator and operands for the operation required, and calls the SimpleCalc bean to perform the calculations. This bean allows you to investigate MockEJB's support for inter-bean references.
  • MessageCalc is a message-driven bean that listens for requests via a JMS queue, extracts the body of any text messages received, and uses the ParsingCalc bean to evaluate them, returning the result of the calculation to the JMSReplyTo destination of the request message. This bean allows you to investigate MockEJB's support for JMS and MDB.

The general process for using MockEJB to test your beans is as follows:

  • Call MockEJB to install itself as the default JNDI provider in the current environment (this simply involves calling the static method MockContextFactory.setAsInitial()).
  • Create a JNDI context and mock EJB container instance associated with it (this is simply a case of creating instances of InitialContext and MockContainer).
  • Optionally, create any mock J2EE environment objects required by your beans (for example, JMS factories and destinations) and install them into the JNDI directory ( for example, by creating objects from the com.mockejb.jms package and calling context.rebind() to associate them with a name in the mock JNDI directory).
  • Create deployment descriptors for your beans to describe them to the framework. MockEJB deployment descriptors are Java objects, rather than XML documents, and are created by constructing objects of the right class (such as SessionBeanDescriptor) with constructor parameters that define the interfaces and bean instance to deploy.
  • Finally, the mock container's deploy() method can be called for each deployment descriptor object to deploy the beans and make them available for testing.

Once this simple process is complete, the beans can be accessed via the standard J2EE lookup/narrow/invoke process that you are already familiar with.

Testing simple EJBs

To illustrate the process, let's start with the simplest possible example and examine how MockEJB allows us to test a simple independent session bean outside the container. The code fragment below shows how the bean is deployed to a local in-memory container for testing:

// Setup the JNDI environment to use the MockEJB 
// context factory
MockContextFactory.setAsInitial();
        
// Create the initial context that will be used for binding EJBs
Context ctx = new InitialContext();
        
// Create an instance of the MockContainer
MockContainer mc = new MockContainer(ctx);

// Create deployment descriptor for our sample bean
// This is used instead of an XML descriptor
SessionBeanDescriptor dd = new SessionBeanDescriptor(
   "java:comp/env/ejb/SimpleCalc", 
   SimpleCalcHome.class, SimpleCalc.class,
   new SimpleCalcBean()) ;
    
// Deploy our bean to the container allowing it to
// be found via JNDI and tested
mc.deploy(dd);

This code has set up the environment to use MockEJB's mock JNDI implementation, rather than a container-based one, create a mock EJB container to deploy our bean to, and then deploy the bean to the container by describing it via a SessionBeanDescriptor object. This use of a Java object as a bean deployment descriptor is the main difference that you'll notice between MockEJB's container and a real application server EJB container. As you can see from the code, creating the descriptor for a bean is simple and just involves constructing it by specifying the JNDI name it should be bound to, the classes that provide the home and remote interface definitions, and a bean class instance to deploy.

Once the bean has been deployed to our mock container, we can write tests against it as if it were deployed to a conventional application server container. The JUnit test method below shows the code needed to call the business methods of our sample bean:

public void testTwoPlusTwo() throws Exception
{
    // Look up the home
    Context ctx = new InitialContext();
    Object ejbObj = 
        ctx.lookup("java:comp/env/ejb/SimpleCalc");
    
    // Narrowing is not needed with MockEJB or WebLogic, but 
    // we call it anyway for standardization
    SimpleCalcHome home = (SimpleCalcHome)
       PortableRemoteObject.
          narrow(ejbObj, SimpleCalcHome.class);
    SimpleCalc calc = home.create();
    assertEquals("Add operator failure", 4.0, 
                  calc.add(2.0, 2.0), 0.0) ;
}

As you can see, this code is identical to the code required to invoke operations on the bean if it were running within an application server container, and so no MockEJB-specific programming is required once the test beans have been deployed. In the sample code associated with the article, the TestSimpleCalcBean JUnit test case class contains this example code for testing the SimpleCalc bean. However, when looking at the sample code, note that that code to perform the MockEJB-specific initialization of the container and deployment of the beans has been factored out of the JUnit test case class into an abstract base class called MockBeanTestBase. This class gives you additional features (such as running inside the EJB container) and avoids duplication of code between tests.

Pages: 1, 2, 3, 4

Next Page ยป