Skip to Content

Automatic mock creation with JUnit & Mockito

Mockito is really a great mocking framework. It is based on a powerful stubbing and verification mechanism. Using it is as simple as this:

import static org.mockito.Mockito.*;

List mockedList = mock(List.class);

mockedList.add("one");
mockedList.clear();

verify(mockedList).add("one");
verify(mockedList).clear();

A handy tool provided by Mockito is a custom JUnit runner that automatically creates mock for fields tagged with @Mock annotation:

@RunWith(MockitoJUnit44Runner.class)
public class ArticleManagerTest {
    @Mock private ArticleCalculator calculator;
    @Mock private ArticleDatabase database;
    @Mock private UserProvider userProvider;

    private ArticleManager manager;

In our team, we came up with an even simpler solution. All mock names should start with mock to ease test code readability. So we coded a custom Runner that doesn’t need the @Mock annotation.

@RunWith(AutoMockRunner.class)
public class ArticleManagerTest {
    private ArticleCalculator mockCalculator;
    private ArticleDatabase mockDatabase;
    private UserProvider mockUserProvider;

    private ArticleManager manager;

Here is the runner implementation:

public class AutoMockRunner extends BlockJUnit4ClassRunner {
  public AutoMockRunner(Class< ?> clazz) throws InitializationError {
    super(clazz);
  }

  @Override
  protected Object createTest() throws Exception {
    Object clazz = super.createTest();

    for (Class< ?> c = clazz.getClass(); c != Object.class; c = clazz.getSuperclass()) {
      scan(testClass, c);
    }

    return clazz;
  }

  private static void scan(Object testClass, Class< ?> clazz) {
    for (Field field : clazz.getDeclaredFields()) {
      if (field.getName().startsWith("mock")) {
        Object mock = Mockito.mock(field.getType(), field.getName());

        try {
          if (field.isAccessible()) {
            field.set(testClass, mock);
          } else {
            field.setAccessible(true);
            try {
              field.set(testClass, mock);
            } finally {
              field.setAccessible(false);
            }
          }
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        }
      }
    }
  }
}
comments powered by Disqus