Easymock … or taking the pain out of (j)unit tests

What are Unit tests?

Unit tests are the lowest level of testing, they are whitebox tests, which means you know what the code does do. Unit tests are for testing methods of a class independently without relying to other classes or services.

This sounds good in theory, but can lead to many problems in real life, especially in J2EE enviroments, as the class you are testing depends on lots of other things, from a database connection to http request parameters.
This is one of the reasons why Unit Test Frameworks like JUnit are often (mis-)used as integration tests, for example by providing a database connection in your test. But with a database connection what are you testing ? Your code ? the state of the Database ? The OR-Mapper ? This would be a Black-Box test with too many unknown and out-of-scope variables, you would never know where in which part the error could be.
Thats why it is still very usefull to have unit tests, even if they seem hard and cumbersome to write.

Enter Easymock

With easymock it is possible to mock every Object that has an Interface. Mocking means that the actual implementation of the interface will be replaced with a dummy placeholder class that you can fill with behaviour. For example you could create a mock from HttpServletRequest which you could use to pass request parameters to your class. Another example would be to replace the database connection classes (DAOs) with mocks, so your test class does need a database anymore.

Lets look at an easy example:

public class User {
    public String name;
    public String password;
    public Integer active;
}
public interface UserDao {
     public User find(String name);
}

The actual implementation would connect to the database and fetch the User Object with the matching name.
Now, lets think we would want to test an UserService, which would use the dao to locate an user, test if the user is active and return
the user object or null if the user is inactive. The implementation (with a dependency injection framework like guice) would look like this:

public class UserService {
   private UserDao dao;

   @Inject
   public Userservice(UserDao tempDao)  {
      dao = tempDao;
   }
  
   public User logon(String name) {
       User tempUser = dao.find(name);
       if (tempUser.active > 0) return tempuser;
       return null;
   }
}

Now this implementation has a simple bug inside, what happens if the dao didn’t find the user ? How would a testcase find that bug ? A first draft could look like this:

import static org.easymock.EasyMock.*;
...
@Test
public void testUserLogon() {
   UserDao mockDao = createMock(UserDao.class);
   fred = new User(1, "Fred",1);
   joe = new User(2,"Joe",-1);
   expect(dao.load(1)).andReturn(fred);
   expect(dao.load(2)).andReturn(joe);
   replay(dao);
   // now we initialize the service with the mocked DAO Object !
   UserService serviceToTest = new UserService(dao);
   User result = serviceToTest.logon("fred");
   assertNotNull(result);
   assertSame(1,user.id);
   result = serviceToTest.logon("joe");
   assertNotNull(result);
   assertSame(2,user.id);

   result = serviceToTest.logon("Unknown");
   assertNull(result);
}

Now, with the help of AtUnit we can simlify the code a lot:

@RunWith(AtUnit.class)
@MockFramework(MockFramework.Option.EASYMOCK) // tells AtUnit to use EasyMock
@Container(Container.Option.GUICE)
public class UserServiceTest {
   @Inject @Unit UserService serviceToTest;
   @Mock UserDao dao;

   @Test
   public void testUserLogon() {
      fred = new User(1, "Fred",1);
      joe = new User(2,"Joe",-1);
      expect(dao.load(1)).andReturn(fred);
      expect(dao.load(2)).andReturn(joe);
      replay(dao);
      User result = serviceToTest.logon("fred");
      assertNotNull(result);
   }
}
This entry was posted in java, Testing and tagged , , , . Bookmark the permalink.

Leave a Reply