tomee-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Quintin Beukes <quin...@skywalk.co.za>
Subject Re: Hackety hack: @Test, @LocalClient and @Stateless for simple JPA testing
Date Fri, 02 Oct 2009 20:45:49 GMT
Just a note - something I learned from painfully.

This is regarding JTA transactions and unit testing.

If you do your unit tests, try and use the EJBs your testing close as
possible as to how you would really call them. If you're making
separate EJB calls from OUTSIDE a JTA transaction, you should also
unit test these calls separately. If you wrap them inside a
transaction while unit testing, but they're not in production (or the
other way around), you might start noticing the one working and the
other failing with errors. This is especially noticeable when more
than one transaction is in the loop (like with multiple persistence
units).

Just thought I'd mention this, before you start digging through weird
hard to explain errors.

Quintin Beukes



On Fri, Oct 2, 2009 at 10:42 PM, Quintin Beukes <quintin@skywalk.co.za> wrote:
> If you really only want to test the JPA entities, and don't mind the
> transactions, why not remove the @Stateless and @EJB completely, and
> just make your test @LocalClient and inject an entity manager?
>
> If this is not the case, why exactly do you need the JTA? In this case
> just split up the test case and the EJB. That double injections of the
> entity manager and EJB seems ugly.
>
> Quintin Beukes
>
>
>
> On Fri, Oct 2, 2009 at 7:20 PM, Laird Nelson <ljnelson@gmail.com> wrote:
>> 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
View raw message