Testing Entity Beans

Java Development News:

Testing Entity Beans

By N. Alex Rupp

01 Jun 2006 | TheServerSide.com

Part 1: Testing Inside the Container
Part 2: Testing Entity Beans
Part 3: Advanced Testing Techniques


"Testing EJBs in a fake container is like trying to test java objects in a fake VM." David Blevins, OpenEJB.

Introduction

This article discusses how to use OpenEJB's container driven testing features to simplify and supercharge your EJB testing.

All the EJB testing philosophies out there involve building up an elaborate but ultimately fake environment within which to test your beans, separating you and your tests from EJB and the Container. This approach is a dead end. The real answer is to test your beans as close to the EJB Container as you can get—directly inside the Container. Container driven testing lets you write more isolated, fine-grained and robust unit tests. Your EJB applications are EJB applications! Admit it! Test them as such!


Testing Inside the Container

In order to understand the advantages of the OpenEJB approach to testing, you first need to understand a few details about the EJB specification. The EJB spec uses different terms for the EJB Container and the EJB Server, but never clearly and explicitly defines the distinction between the two. OpenEJB defines an explicit contract in order to separate the concerns of the Container and the Server. This explicit division of roles is central to the OpenEJB architecture and is a key to its uniquely embeddable nature.

The terms "EJB Container" and "EJB Server" are abstract and not defined by the spec in terms of concrete implementation detail. In OpenEJB's world however, the Container has the basic job of holding instances and running them through their lifecycle, the Server's job is to extend the bean's interfaces to clients and delegate calls to the Container.

The OpenEJB project has published an illustration of the Container / Server breakdown . OpenEJB has two implementations of EJB Server available, the Local Server (aka IntraVM) and the Remote Server.

If you compare the pictures from the Local and Remote Server pages, you start to get an idea of how an implemented server looks. When you run OpenEJB embedded, you are just using the Local Server to get at beans. In fact, the beans in the Container are also using this Server when they look each other up through JNDI.

The Remote Server is a more complex, as it listens on a socket for incoming requests from clients. When a request comes in on the socket, it reads in the data, launches off a thread which is used to delegate the call to the container, then goes back to listening for more requests. Sounds simple, but there is a lot of overhead to anything network based; protocols, thread pools, serialization and deserialization, communication performance, network security, class distribution, etc.

The Server layer in Geronimo will do all the same things as the Remote Server, but add in clustering, load balancing, and other advanced functionality. The Server layer in Apple's WebObjects also does the same thing as the Remote Server, but does so using CORBA's IIOP protocol via OpenORB.

If you mentally compare the descriptions of the Server implementations described, you begin to see how EJB Servers can get so heavy. Because OpenEJB separates the interface distribution concerns from the instance management concerns, it can be made as light or as heavy as you need it.

Starting up a full-blown EJB Server would add a lot of overhead to your testing process. If you only need the EJB container functionality, this overhead would be overkill. On the other hand, some of your tests might need to be run against a full-blown EJB Server. To date, most testing frameworks for EJB focus on simulating an EJB Container environment, because the EJB Container cannot be cleanly separated from any of the commercial EJB Servers. The flaw in this strategy is that developing an EJB testing framework eventually becomes as complex as developing a real EJB Server.

Conversely, OpenEJB is specifically designed to be embedded—especially for unit testing. The OpenEJB project uses test-driven development, and its developers need a way to automatically test the capabilities of their own container. To achieve this, they built a framework extending JUnit and leverage their unique architecture to isolate the container and perform lightning-fast unit tests directly against the EJB Container. This helps them make sure the Container is functioning the way it should, and gives you the ability to run tests on your EJBs.

Here is where OpenEJB really shines. The ability to embed the EJB Container, coupled with the ability to selectively include the full EJB Server environment lets you can write robust tests for the following functionality:

  • Transaction integrity
  • Multithreaded behavior
  • The effect of static variables and singletons at runtime
  • How components will run when deployed in concert
  • How components will run when they're alone
  • Component behavior at different points in the EJB lifecycle
  • Simulated RMI client calls
  • CRUD operations for entity beans
  • Proper serialization of Stateful Session Beans

This is by no means a complete list. If not planned for and implemented properly, these issues and many others could wreak silent havoc in a production environment. Outside of a Container, it is almost impossible to reliably test these areas.

OpenEJB lets you determine how little or how much of the Container and Server you want to include.

By taking advantage of OpenEJB for container driven testing, you can dramatically improve your test's capabilities without saddling them with ugly code or a complicated infrastructure. In fact, testing with OpenEJB doesn't require you to lace your test code with any OpenEJB specific or non-compliant APIs. Not only can you write more robust container driven tests, but you can do it without API lock-in.

Sound good? It gets better. You can also automate the entire testing package using a simple Maven build that I've already written for you, and (believe it or not), you don't even need to install OpenEJB.

Enough talk. Let's fire up our container and run some tests.


Getting started

The following directions are for setting up and running the example application in a Windows environment. If you're working in a Unix environment, make sure to change the path to the installation directory in the /conf/openejb.conf file and make sure JAVA_HOME and MAVEN_HOME are on your classpath. Maven's a breeze--you'll have no problem keeping up.

Install the JDK

  1. Install J2SDK 1.4.2 to the default directory C:j2sdk1.4.2_04
  2. Set the JAVA_HOME variable:
  3.  C:> set JAVA_HOME=C:j2sdk1.4.2_04
    

Install Maven

  1. Download http://apache.mirrors.redwire.net/maven/binaries/maven-1.0-rc2.zip
  2. Unzip to C:
  3. Check your installation:
  4.  C:>dir maven-1.0-rc2 Directory of C:maven-1.0-rc2 05/09/2004 02:00p <DIR> . 05/09/2004 02:00p <DIR> .. 05/09/2004 02:00p <DIR> bin 05/09/2004 02:00p <DIR> lib 03/23/2004 02:53p 2,491 maven-navigation-1.0.xsd 03/23/2004 02:53p 14,760 maven-project.xsd 05/09/2004 02:00p <DIR> plugins 2 File(s) 17,251 bytes 5 Dir(s) 6,253,555,712 bytes free
    
  5. Set the MAVEN_HOME variable:
  6.  C:> set MAVEN_HOME=C:maven-1.0-rc2
    
  7. Add %MAVEN_HOME%/bin to your PATH variable:
  8.  C:> set PATH=%PATH%;%MAVEN_HOME%bin
    
  9. Check to make sure maven is in your PATH:
  10.  C:> maven --version __ __ | / |__ _Apache__ ___ | |/| / _` V / -_) ' ~ intelligent projects ~ |_| |___,_|_/___|_||_| v. 1.0-rc2
    

Install the EJB Testing Examples

  1. Download http://www.openejb.org/ejb-testing-examples-part01.zip
  2. Unzip to C:
  3. Check your installation:
  4.  C:>dir ejb-testing-examples-part01 Directory of C:ejb-testing-examples-part01 05/16/2004 08:09p <DIR> . 05/16/2004 08:09p <DIR> .. 05/16/2004 07:53p <DIR> example_01 0 File(s) 0 bytes 2 Dir(s) 15,507,103,744 bytes free C:>dir ejb-testing-examples-part01example_01 Directory of C:ejb-testing-examples-part01example_01 05/16/2004 08:29p <DIR> . 05/16/2004 08:29p <DIR> .. 05/16/2004 02:04p <DIR> conf 05/16/2004 04:21a 3,440 maven.xml 05/16/2004 12:11a 440 project.properties 05/16/2004 07:52p 4,155 project.xml 05/16/2004 02:04p <DIR> src 4 File(s) 8,347 bytes 4 Dir(s) 15,506,739,200 bytes free
    

Compile & Test Your Session Beans

  1. Go to C:ejb-testing-examples-part01example_01
  2.  C:>cd ejb-testing-examples-part01example_01
    
  3. Build the EJB JAR and run the session bean tests:
  4.  C:ejb-testing-examples-part01example_01>maven __ __ | / |__ _Apache__ ___ | |/| / _` V / -_) ' ~ intelligent projects ~ |_| |___,_|_/___|_||_| v. 1.0-rc2 Attempting to download openejb-core-1.0-SNAPSHOT.jar. build:start: default: java:prepare-filesystem: java:compile: [echo] Compiling to C:ejb-testing-examples-part01example_01/target/classes java:jar-resources: test:prepare-filesystem: test:test-resources: test:compile: test:test: jar:jar: aspectj:init: jar: validate: java:prepare-filesystem: java:compile: [echo] Compiling to C:ejb-testing-examples-part01example_01/target/classes java:jar-resources: test:prepare-filesystem: test:test-resources: test:compile: test:test: [junit] Running com.nrfx.articles.openejb.Example01Test [junit] Tests run: 34, Failures: 0, Errors: 0, Time elapsed: 4.356 sec [junit] Running com.nrfx.articles.openejb.Example02Test [junit] Tests run: 34, Failures: 0, Errors: 0, Time elapsed: 4.406 sec BUILD SUCCESSFUL Total time: 20 seconds
    

If everything went off correctly, you've just run unit tests on an EJB Session components directly against an embedded EJB Container. No framework in the middle. No assembly required. You didn't even need to install OpenEJB--everything required in order to compile, validate and load your enterprise components into the EJB Container was either in this simple build, or has since installed itself.

Once the enterprise component JAR is compiled, assembled and validated, the tests run extremely fast. The output above came out of my old Pentium III. Just imagine how fast this would run on a modern machine!

One of the reasons these tests run so fast is that OpenEJB doesn't "hot deploy" the beans. There is one startup phase where beans are loaded and that is it. Hot deploy stategies aren't failsafe and frequently don't work; requiring you to manually stop and start the server anyway. Hot deploy is a feature for very large environments with both several running applications and continuous availability needs. It is certainly not required for testing, development or any production environment with just a single application. Cutting it out speeds things up significantly and removes a major complaint people have with most EJB servers.

Another reason the tests run so fast is that OpenEJB doesn't generate EJBC stubs or compile the bean components in the container. Instead, it uses dynamic proxies to load the beans—a strategy shared by at least one other EJB Container vendor.

A third speed-boost is gained from validating each EJB for basic spec compliance before loading it into the container. We'll go over this in more detail later on.

Suffice to say this strategy works. You can test EJBs directly against an embedded EJB Container, and you can do it fast. Next we're going to take a look at how you do it, starting with a simple Session Bean test.


A Sample Test Case

At this time we're going to step inside of one of the test case classes, and see how an EJB unit test is assembled.

 package com.nrfx.articles.openejb; import java.util.Properties; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; import junit.framework.TestCase; public class Example01Test extends TestCase { protected ExampleHome ejbHome; protected Example ejbObject; private String name="nrfx/examplebean"; public Example01Test() throws Exception { InitialContext context = new InitialContext( System.getProperties() ); Object obj = context.lookup(name); ejbHome = (ExampleHome)PortableRemoteObject. narrow( obj, ExampleHome.class); ejbObject = ejbHome.create(); } public void test01_returnStringObject() { try{ String expected = new String("1"); String actual = ejbObject. returnStringObject(expected); assertEquals(expected, actual); } catch (Exception e){ fail("Received Exception " + e.getClass() + " : "+e.getMessage()); } } // ... }

The first thing you should notice about this simple example test is that there are no OpenEJB specific APIs or hard-coded properties used to find the InitialContext. This is of critical importance; it means that your tests are not bound to the OpenEJB API, and that your tests will not be locked in to a specific EJB Container implementation. OpenEJB does not need to be your production server in order to use it for testing. Furthermore, the tests you write could actually be run against another server provided you put the right JNDI parameters in project.properties and deployed the beans using that server's tools. These are normal unit tests, and are 100% EJB compliant.

All the magic is in the creation of the InitialContext object which is required to access any EJB. When org.openejb.client.LocalInitialContextFactory is used as the JNDI provider, it will automatically embed OpenEJB into the testing VM. Afterwards, the same instance of OpenEJB is used for all the tests within that VM. This gets a bit tricky when you're running tests inside an automated build environment like Maven, because Maven creates a new VM for each test class.

Notice, also, how the JNDI call uses the system properties instead of hard-coded properties. If the above example didn't have to be squished down to a 50 character wide column, you could get your InitialContext to the EJB Container in one Container-agnostic line of code.

Finally, we didn't get our InitialContext to the Container in the setUp() method. That's because we'd have to re-create the context object for every single test method in the class. This would unnecessarily slow down our tests.

Once you've got the initial setup for your test class written, you can add as many test methods as you like.

The functionality we're testing is a bit simplistic, but it gets the point across. Once you've got your bean component, you can isolate its different API features and hammer away at them until you're satisfied the component is doing what it should.

Coming Up

We've only just barely scratched the surface. The next two sections in this series will cover testing Entity Beans, and advanced testing techniques.


About the Author

N. Alex Rupp is a professional Open Source developer and software architect for Open Technology Systems, a Twin Cities firm dedicated to helping small and medium sized companies participate in the Open Source software movement. He frequently writes code at the Dunn Brothers coffee shop in southeast Minneapolis. He is also President of the Twin Cities chapter of IASA, the International Association of Software Architects, and JSR-94 implementation lead for Drools, a dynamic rule engine project at The Codehaus.
He can be reached at alex@nrfx.com

Related Content

Related Resources