Mock objects with EasyMock

1. Introduction

The mock objects allows to make unit tests on objects depending on other objects. We will replace this dependencies with mock objects. With that, we can by example verify than the method xyzzy() has been called 5 times and returned 33. That can be practical in a several cases. By exampe, if the object to mock is slow or undeterministic (depending on time, or why not on the weather). This objects are really difficult to test because we can make a lot of tests but we could never find the special cases. Test cases with mock objects enable us to test this cases.

There is several tools to make mock objects. In this article, we will use EasyMock 2.5.2 with JUnit 4.7.

Here is the interface to test :

public interface ISimpleDao {
    void save(String title);
    void remove(String title) throws NotExistingException;
    int count();
    void debug();
    boolean isValid(String title);
    void insert(String title);
}

And here is our class to test :

public class SimpleService {
    private ISimpleDao dao;

    public void setDao(ISimpleDao dao){
        this.dao = dao;
    }

    public void insert(String title){
        if(dao.isValid(title)){
            dao.insert(title);
        }
    }

    public void save(String... titles){
        for(String title : titles){
            dao.save(title);
        }
    }

    public boolean remove(String title){
        try {
            dao.remove(title);
        } catch (NotExistingException e){
            return false;
        }

        return true;
    }

    public int size(){
        return dao.count();
    }

    public void debug(){
        System.out.println("Debug informations of SimpleService");
        dao.debug();
    }

Our mock will implement the ISimpleDao interface and we will give it to SimpleService who's the class to test. This example is really simplistic, but it will be enough to cover the main features of EasyMock.

2. Verify a behaviour

Here is the structure i will use in this article :

import org.junit.Before;

import org.junit.Test;
import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;

public class SimpleServiceTest {
    private SimpleService simpleService;
    private ISimpleDao simpleDaoMock;

    @Before
    public void setUp(){
        simpleService = new SimpleService();
        simpleService.setDao(simpleDaoMock);
    }

    @Test
    public void insertValid(){}

    @Test
    public void insertNotValid(){}

    @Test
    public void save(){}

    @Test
    public void removeWithoutException() throws NotExistingException {}

    @Test
    public void removeWithException() throws NotExistingException {}

    @Test
    public void size(){}

    @Test
    public void debug(){}
}

First of all, we'll start with create a mock object. For that, we've to use the EasyMock class and its method createMock, with the interface in parameter. To improve code readability, we use a static import like what we do in general with JUnit.

import org.junit.Before;

import org.junit.Test;
import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;

public class SimpleServiceTest {
    private SimpleService simpleService;
    private ISimpleDao simpleDaoMock;

    @Before
    public void setUp(){
        simpleDaoMock = createMock(ISimpleDao.class);

        simpleService = new SimpleService();
        simpleService.setDao(simpleDaoMock);
    }
}

This will create a mock objet implementing ISimpleDao interface. The first thing we can do with EasyMock is verify than a method has been called. EasyMock works like a recorder :

  • We play the desired sequence on the mock object.
  • We record the played sequence.
  • We test the object
  • We verify that the test sequence correspond to the recorded one

So, we'll test to start that the debug() method of SimpleService call the debug() method of our Dao :

@Test
public void debug(){
    simpleDaoMock.debug();
    replay(simpleDaoMock);
    simpleService.debug();
    verify(simpleDaoMock);
}

The replay method enable to save the record and the verify method compare the two records are equals. If not equals, the verify method will launch AssertionError. If you launch the written test, it will executes fines, but if we comment the dao.debug() statement in SimpleSerivce, the test will fail :

java.lang.AssertionError:
  Expectation failure on verify:
    debug(): expected: 1, actual: 0
    at org.easymock.internal.MocksControl.verify(MocksControl.java:111)
    at org.easymock.EasyMock.verify(EasyMock.java:1608)
    at com.dvp.wichtounet.easymock.SimpleServiceTest.debug(SimpleServiceTest.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:94)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:165)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:110)

So, EasyMock has detected that the method has not bee called and the test fails. If you want to verify that a non-void method has been called , you will have an IllegalStateException because no return behaviour has been specified. We will see that in the next chapter.

3. Wait for return values

We will now work with methods returning values. In this case, we've to define a return behaviour. To do that, we must use the expect() method to encapsulate the call and the andReturn() method to specify a return value. Here is how we can test the size() method :

@Test
public void size(){
    expect(simpleDaoMock.count()).andReturn(32);
    replay(simpleDaoMock);
    assertEquals(32, simpleService.size());
    verify(simpleDaoMock);
}

With that, we make two tests, we verify that the count method has been called and that size() return the same value as count(). That is the case if we launch the test. We can see that it's really simple to specify a return value for a mocked method.

4. Work with exceptions

EasyMock can also work with exceptions. We can use again the expect() method, but this times we will use the andThrow method to specify the throwed exception. Here is what we can do with the remove() method test with and without exception :

@Test
public void removeWithoutException() throws NotExistingException {
    simpleDaoMock.remove("Mary");
    replay(simpleDaoMock);
    assertTrue(simpleService.remove("Mary"));
    verify(simpleDaoMock);
}

@Test
public void removeWithException() throws NotExistingException {
    simpleDaoMock.remove("Arthur");
    expectLastCall().andThrow(new NotExistingException());
    replay(simpleDaoMock);
    assertFalse(simpleService.remove("Arthur"));
    verify(simpleDaoMock);
}

Once again, only one method call is enough to specify a behaviour. I think it's here that we can see the power of mocks objects.

5. Miscellaneous

5.1. Verify the number of calls

Now we can test the save() method :

@Test
public void save(){
    simpleDaoMock.save("xyzzy");
    simpleDaoMock.save("xyzzy");
    simpleDaoMock.save("xyzzy");
    simpleDaoMock.save("xyzzy");
    simpleDaoMock.save("xyzzy");

    replay(simpleDaoMock);

    simpleService.save("xyzzy", "xyzzy", "xyzzy", "xyzzy", "xyzzy");

    verify(simpleDaoMock);
}

This kind of code is really heavy to write with a high number of calls. We have two solutions. We can do a loop for all the calls or use the times() method of EasyMock :

@Test
public void save(){
    simpleDaoMock.save("xyzzy");

    expectLastCall().times(5);

    replay(simpleDaoMock);

    simpleService.save("xyzzy", "xyzzy", "xyzzy", "xyzzy", "xyzzy");

    verify(simpleDaoMock);
}

A lot clearer, no ? It's also possible to specify that a method must called any times with the anyTimes() method and an interval of times with the times(min,max) method.

5.2. Verify calls order

We will now test the insert() method :

@Test
public void insertValid(){
    expect(simpleDaoMock.isValid("Arthur")).andReturn(true);
    simpleDaoMock.insert("Arthur");
    replay(simpleDaoMock);
    simpleService.insert("Arthur");
    verify(simpleDaoMock);
}

@Test
public void insertNotValid(){
    expect(simpleDaoMock.isValid("Arthur")).andReturn(false);
    replay(simpleDaoMock);
    simpleService.insert("Arthur");
    verify(simpleDaoMock);
}

You're going to say that we've already seen all that stuff. But in that kind of case, it could be interesting to verify that the calls are in the good order. Indeed, if the method isValid() is called after the insert, that's really useful. With EasyMock, there is two ways to verify calls order. First, you can use the createStrictMock insted of createMock to create your mock or you can use the checkOrder(mock, true) method to specify that the mock is strict. A strict mock is simply a mock who cares about the order of the calls. So we can keep all our tests in the current state and just use one of this two methods and the order will be checked. Of course, we can verify the order only in certain tests methods. That can be done using checkOrder(mock, true) at the start of the test method.

5.3. Mock a class

EasyMock has an extension to mock classes and not interfaces. It's EasyMock Class Extesion. All the use is the same, we just have to use this import :

import static org.easymock.classextension.EasyMock.*;

Moreover, we can also make a partial mocking with by example only one method :

Mocked mock = createMockBuilder(Mocked.class).addMockedMethod("mockedMethod").createMock();

Keep in mind that the final classes are not supported and that the final methods are not mocked.

6. Conclusion

So, we have seen all the features of EasyMock to create mock objects for unit tests. Like you've seen, it's a really simple but powerful way to verify the behaviour of an object depending on an other. There are others libraries for mock objects like JMock, JMockit or Mockito, but personally, i think EasyMock is most comfortable to use and give all the features i need to make my own unit tests. That's why i choose this library to make this article.

I hope this article has interested you. Don't hesitate to comment it ;)

Related articles

  • Java 7 : More dynamics
  • Java 7 : The new java.util.Objects class
  • The reserved keywords of the Java Language
  • Creation of Swing User Interface : Tables (JTable)
  • Java 7 : Add "public defender methods" to Java interfaces
  • Catch: A powerful yet simple C++ test framework
  • Comments

    Comments powered by Disqus