Someone mentioned a mocking framework called Mockito some time ago to me. I am familiar with mocking frameworks, as I work with EasyMock quite a lot. I really like EasyMock, but I am curious about Mockito. I thought of trying it out a bit and write down my experiences along with a comparison with EasyMock.
This is by all means not a very in-depth comparison, but I did find out some interesting things.
In order to test out the mocking frameworks I have set up some code in place to test. The code to be tested is an ‘itemRepository’ (It is however, not a full implementation of the Repository Pattern). Typically you use it to get some stuff (Items). In this case the Item is retrieved from a Dao object used by the repository. Just for easiniess the DAO returns the same object as the repository. (The repository pattern makes a distinction between the object the DAO returns and the Domain objects the Repository should return).
Here is the code of the ItemRepository:
public class ItemRepositoryImpl implements ItemRepository { private ItemDao itemDao; @Override public Item getItem(String someInput) { return itemDao.getById(Long.valueOf(someInput)); } public void setItemDao(ItemDao itemDao) { this.itemDao = itemDao; } public ItemDao getItemDao() { return itemDao; } }
My goal is to test the ItemRepository’s getItem method. And all I care about is that the itemDao is correctly called with the correct parameters. Hence this is what a collaboration test is all about.
Lets start with my comfort zone: EasyMock
The test class I write talks to interfaces. I find it a good habit to talk against interfaces and not concrete implementations. Doing that however, forces me to cast to an implementation to set collaborators in the tests. Normally such things happen in the @Before. But since I will also create a test with the Mockito framework I have it done in the test method itself.
The begin of the test:
public class ItemRepositoryTest { private ItemRepository itemRepository; private ItemDao itemDao; @Before public void setUp() { itemRepository = new ItemRepositoryImpl(); }
In line of the tripple A testing guidelines I have an arrange, act and assert:
@Test public void mustReturnItemFromMockedItemDao_EasyMock_Behaviour() { ItemRepositoryImpl impl = getItemRepository(); itemDao = EasyMock.createMock(ItemDao.class); impl.setItemDao(itemDao); // this is weird: I don't *want* to bother about returning stuff here, just that it is called! // mocking and stubbing is combined here EasyMock.expect(itemDao.getById(1L)).andReturn(null); EasyMock.replay(itemDao); // Act itemRepository.getItem("1"); // Verify EasyMock.verify(itemDao); }
As you can see I have pointed out one thing of EasyMock’s behaviours with a comment. Whenever you mock a method that has a return type, EasyMock expects you to fill in that behaviour. If you don’t do that, you’ll end up with an exception like this:
java.lang.IllegalStateException: missing behavior definition for the preceding method call getById(1)
In this case I have ‘solved’ it by returning null. While writing the test, I did not want to be bothered about it, but I have to satisfy EasyMock. Doing so reduces the readability of my code. The intention of the code remains unclear at this point, and that’s something I’d like to avoid as much as I can.
Another well known behaviour of EasyMock is the need to replay your mock after you have set the expectations. Using a ‘recorder’ metaphor it sounds reasonable. But basically you’re writing the behaviour ‘twice’: First you write down the expectations, then you actually run them. Writing the expectations is often found to be a cumbersome job to do, especially with multiple collaborators.
And of course at the end it all needs to be verified. Which is done by EasyMock.verify. We could even check the outcome. Most of the time you’re tempted to do so, you had to write the return value anyway. Better test if the return value being returned is the same as the method returns right? I think not. Reason: your intention of your test becomes unclear if you assert this as well. And as a bonus you introduce your tests to be more fragile. The unit test becomes now a collaborator test and a value-based test in one. Mockito makes this distinction very clear.
Mockito:
@Test public void mustReturnItemFromMockedItemDao_Mockito_Behaviour() { // Arrange ItemRepositoryImpl impl = getItemRepository(); itemDao = Mockito.mock(ItemDao.class); impl.setItemDao(itemDao); // Act itemRepository.getItem("1"); // Assert / verify Mockito.verify(itemDao).getById(1L); }
Plus:
– no need to mock return etc, as we dont care
– seperation of mocking and stubbing (stubbing is done by using the static method when, mocking by using verify).
So how about stubbing in Mockito? Here is how you stub the itemDao:
@Test public void mustReturnItemFromMockedItemDao_Mockito_Stubbing() { // Arrange ItemRepositoryImpl impl = getItemRepository(); itemDao = Mockito.mock(ItemDao.class); impl.setItemDao(itemDao); Mockito.when(itemDao.getById(1L)).thenReturn(null); // Act itemRepository.getItem("1"); }
For more information about Mockito, they also have a more extensive comparison between EasyMock and Mockito.
Do you have any experience using Mockito and EasyMock and you would like to share some insights? Please leave a comment.
Someone pointed at RhinoMocks also being available for Java. I’m not so sure about that. However, if you do know about a Java variant, let me know so I can compare it as well.