Saturday, 4 June 2011

Prefer Injecting EJBs via Setter Methods

If you read many of the EJB3 texts you’ll see that they advise you to use the @EJB annotation to inject one ejb into another. This is all good and fine as in a deployment situation the container will neatly inject one bean into another, but, and here’s the problem, all the books and info that I can find on the Internet always recommend that you annotate your injected instance variable. For example, in yesterday’s blog I defined a very simple User ejb and if we use the recommended method for injecting it into another ejb, then we’d annotate our other ejb’s instance variable like this:

  @EJB
 
private User user;

This will work; however, getting back to the but we need to consider how we’re going to test our new ejb: the @EJB only works in a container manged environment and simple JUnit tests are not container managed. What we should be doing is writing our ejb, together with it’s unit tests using TDD ensuring that our code is solid before it’s deployed on our server.

The solution to this is to annotate a setter method. In the case of an injected User ejb, then the code would look like this:

  private User user;

 
@EJB
 
public void setUser(User user) {

   
this.user = user;
 
}

Using a simple setter method gives us so much more control over the code, allowing us to write JUnit tests using either classical or mockist testing techniques. For example, suppose we create a new ejb call EjbUnderTest that has method called doBusinessCase(). With a setter method annotated as shown in the code above we can write a JUnit test that will test the doBusinessCase() method as shown in the snippet below:

    EjbUnderTest testInstance = new EjbUnderTest();
    userMock = createMock
(User.class);
    testInstance.setUser
(userMock);

    expect
(userMock.getUserName(isA(String.class))).andReturn("Freddy the Frog");
    replay
(userMock);

    String result = testInstance.doBusinessCase
();

    verify
(userMock);

    assertNotNull
(result);
    assertTrue
(result.contains("Australia"));

In writting the unit test, we can prove our doBusinessCase() code works in isolation from the User ejb and that it’s correct, plus it has been tested without using a server. In many environments this will save a great deal of time as packaging and deploying ejb code is often a costly exercise.

No comments: