tomee-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Laird Nelson <ljnel...@gmail.com>
Subject Hackety hack: @Test, @LocalClient and @Stateless for simple JPA testing
Date Fri, 02 Oct 2009 17:20:56 GMT
This falls under the category of interesting hacks.  It also falls under the
category of "the goggles...they do nothing!".  But it's Friday.

So I'm unit testing, and wanted to use OpenEJB's ability to run an SLSB in a
transaction really only for the fact that that SLSB could then use an
injected, transactional EntityManager without hassle.

That is, really the thing I want to test is my JPA machinery--the mappings,
the validations, etc.  The easiest way to make this happen is to test an
insert and retrieval with an EntityManager, and the easiest way to get an
entity manager is to have one injected into a stateless session bean so you
don't have to manage all the transactions for yourself.  But I'm in unit
test mode--I don't really want to create an SLSB and a TestCase for every
stupid JPA scenario I want to test.  Ideally I would {handwave handwave}
have a transactional entity manager injected into my test case for me
somehow but {handwave handwave} run as part of the EJB container {more
handwaving}.  But my test case is not an EJB.  It is at the moment only a
@LocalClient.

Well, so, I made my TestCase both a @Stateless and a @LocalClient.  :-)  It
implements a simple interface that basically defines what methods I want to
have exposed through the local business interface.  Ideally even this step
wouldn't be necessary--once you can have an interfaceless SLSB in EJB 3.1,
you can throw this step out.

I annotate my test methods with @Test (from JUnit).  I inject my @EJB (the
test case itself!) into...uh...itself.  :-)  I also inject an
EntityManager.  Unfortunately the EntityManager shows up both "in" the
test-case-as-EJB and the test-case-as-LocalClient.  I just take care not to
use it in the test-case-as-LocalClient methods.  There is probably a way in
@Before to null it out in such a case; I'll do that next.

Anyhow, the net effect is that I can use an injected EntityManager in my
test case which is effectively wrapped in itself as a SLSB.  That's the part
that makes my eyes go funny.  Anyhow, it makes in-memory JPA testing pretty
painless.

The whole thing looks like this (the abstract test case I'm inheriting from
does the OpenEJB initialization, but not much else; the code below is
condensed for brevity):

import javax.ejb.*;
import javax.persistence.*;
import org.junit.Test;
import junit.openejb.AbstractOpenEJBTestCase;
import org.apache.openejb.api.LocalClient;
import static org.junit.Assert.*;

@Stateless @LocalClient
public class TestCaseXY extends AbstractOpenEJBTestCase implements
TestClient {

  @EJB private TestClient tc; // a reference to...um...myself
  @PersistenceContext private EntityManager em;

  // The JUnit test method.  Don't use the EntityManager here;
  // I think its behavior would be undefined since your
  // persistence.xml should be designating a JTA data source,
  // but you're not in a JTA context here.
  @Test public final void testXYClient() {
    assertNotNull(this.tc);
    this.tc.testXY(); // "Forward" to the "real" test method.
  }

  // The "real" test method.  Run in a transaction, with EJB security, etc.
  @Override public void testXY() {
    assertNotNull(this.em);
    assertNotNull(this.tc);
    assertNotSame(this.tc, this);
    // Actual test code goes here
  }

}

// Interestingly, this doesn't have to be public so you can put it in the
same file.
interface TestClient {
  public void testXY();
}

I hope someone finds this useful; feel free to get in touch (ell jay nelson
at gee mayul dot com) if you have questions.

Best,
Laird

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message