views:

72

answers:

3

How would you go about unit testing an EJB that uses JPA? For example, if I have an Order entity and and OrderEJB that is supposed to calculate the total of an order (as defined below) how would I go about unit testing the EJB without touching the database? Also, how would you define values for your entities, so you can assert the expected calculation? Here is some example code below...

@Entity
public class Order {
    @Id
    private long OrderId;
    private LineItem[] items;
}

And an orderEJB

@Stateless
public class OrderEJB {
    EntityManager em;
    public double calculateOrderTotal(long orderId) { .. }
}

How would you go about unit testing the calculateOrderTotal method if I can't touch the database? I don't want to implement a DAO because I'm trying to move away from that approach.

Thanks for any help.

+3  A: 

Isn't the general theory that OrderEJB and Order and LineItem are (if we ignore the annotation) just POJO and therefore can be tested in stand-alone JUnit? We will need to mock EntityManager, and presumably in

 calculateOrderTotal()

you have some code that in concept goes

 em.giveMeThisOrder(orderId)

and you just mock this. The businesss logic you're testing then gets driven by what the Mock returns. The key to this is that you must use a good mocking framework, for example JMock. In any given test you say (obviusly not with this syntax):

 EntitiyManager mockEm = // create the mock
 mockEm.check(that you are called with and order Id of 73)
 mockEm.please( when someone calls giveMeThisOrder return then **this** particular order)

and so in each test you create exactly the order you need to exercise some aspect of your calcualtion code. You may well have many such tests that push all the edge and corner cases of your calculation.

The key idea here is Unit Test implies no external dependency such as a Database. Integration Testing could use a real database. It can be a hassle to get your mocks right, creating those Order instances can be quite dull, but it does tend to make future testing much quicker.

I do also favour doing early integration testing - you find a whole other class of errors that way.

djna
I agree with this +1
Pascal Thivent
But how would you assert that the calculation is correct, if you don't know what the data is going to be? Do you need to use integration testing to do this? Maybe I'm mixing up the two, I'm a bit confused at what the difference is between integration testing and unit testing...
Brian D.
You **do** know what the data is going to be, I'll update the answer to explain.
djna
A: 

Here's what I do:

First you need to set up an in-memory database for your tests. It works just like a regular database, but it's not stored on disk. Both Derby and HsqlDB support this.

In your unit test, create an EntityManager manually, and inject it into your EJB instance. You'll probably need to keep a reference to the EntityManager so you can manage the transactions, like this:

em.getTransaction().begin();
myEjb.doSomething(x, y);
em.getTransaction().commit();
Mike Baranczak
That's not **unit** testing (it's a valid approach for integration testing, but it's not unit testing).
Pascal Thivent
Well, if I'm testing a single EJB on its own, I'd call that a unit test. You'll probably say that if I'm connecting it to a persistence provider, then I'm not testing it "on its own" - and I guess that's a valid position too, but I don't get paid enough to split hairs.
Mike Baranczak
+3  A: 

Did you give OpenEjb a try? - If you setup in embedded mode you can pretty much run unit tests from eclipse. I have mocked out entity manager injections etc for unit testing before but then it gets tedious. With openejb you can do it with less setup. http://openejb.apache.org/

OpenSource
This wouldn't be **unit** testing (in isolation).
Pascal Thivent
Ofcourse it boils down to how isolated you want to go :) - IMHO the scaffolding you need to create to make it so isolated is not worth it. I would rather throw in openejb and hsqldb to unit test my ejbs without having to worry about creating mocks everywhere. Again just my take - may be it differs from a lot of you out there, I dont know. Also forgot to add this to the original post - http://www.adam-bien.com/roller/abien/entry/how_to_unit_test_ejb
OpenSource
This is a very valid approach for integration-testing. It's just that the OP was explicitly asking about unit-testing (and not touching the database).
Pascal Thivent