Thursday, June 25, 2009

Restarting the embedded OpenEJB container between each test

logo_openejb.gifIf you are looking for an embeddable EJB3 Container for your unit-tests/integration-tests, OpenEJB is currently the most mature solution (alternatives are embedded Glassfish and JBoss embedded).

The documentation and the samples of OpenEJB are really neat and enable an easy jump-start. All the examples are automated tests that run with a simple mvn clean install.

After a while however I came across the following problem: The embedded container is not restarted by default between tests. If you have two tests (even in several test classes), each starting the embedded container, then the second test gets passed the same instance of the embedded container as the first one.

This has the potential for shared state between the tests and strange side-effects as a consequence.
The first occurrence is when you are accessing an (sandboxed) database, that gets initialized (hibernate create-drop) when initializing the persistence-unit. Since the container is not restarted for the second test, the persistence-unit does not get initialized a second time. This means you have all the traces from your first test in the database...

An easy way to work around this, is the undocumented feature of OpenEJB to destroy the container when closing the initial context.
This is achieved by setting the property "openejb.embedded.initialcontext.close" to "destroy" on the InitialContext.

Now my test harness looks like this:
@Before
public void setUp() throws Exception{
	Properties p = new Properties();
		
	//Set some other properties like datasources ...       
	p.put("openejb.embedded.initialcontext.close", "destroy");
        
	context = new InitialContext(p);
}
	
@After
public void tearDown() throws Exception{
	context.close();
}

It should be kept in mind, that restarting the embedded container can have implications on the performance.
In my first tests on my MacBook, the repeated startup of the container takes about 200 ms, which I find acceptable for integration tests... but probably the concrete deployment scenario has an influence on the startup time ...

3 comments:

  1. Hi; excellent article.

    Have you observed that the OpenJPA provider is not restarted when you do this? I'm trying to work around this.

    That is, although a new EJB container is started for each test, the underlying JPA provider (OpenJPA) survives Context.close(). This means that data inserted into an in-memory H2 database, for example, can be seen by two test methods. I haven't found a way to solve this problem.

    ReplyDelete
  2. @Laird

    Sorry, I cannot reproduce your statement.

    If I call

    p.put("openejb.embedded.initialcontext.close", "destroy");

    before creating my InitialContext. And then call

    context.close();

    at the end of each test.
    Then the persistence-unit gets deployed for each test. If you then have your persistence-provider configured to newly create the schema at deployment, you should not have any data surviving between two tests ...

    ReplyDelete
  3. Note "DESTROY" is case sensitive, else the default "LOGOUT" is used. The enum value is taken from:

    LocalInitialContext.Close.DESTROY

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...