Automatic mock creation with JUnit & Mockito

Mockito is really a great mocking framework. It is based on a powerful stubbing and verification mecanism. 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();
        }
      }
    }
  }
}

2 thoughts on “Automatic mock creation with JUnit & Mockito”

  1. hm… I am not convinced. I think it makes it less clear how the mocks are instanciated.

    BTW, I am *also* not a fan of the @Mock annotation. It is an incentive for developers to have common initialisation between tests, as opposed to keeping all things necessary to a test inside the method. You also lose the incentive to have few mocks, since it is less of a pain to have many dependencies in your Class Under Test (an issue that I see on my current project: they have dozens of dependencies in any given class, but don’t care since they can easily instanciate dependencies in their tests with @Mock).

Comments are closed.