Oleg Atamanenko

thoughts about programming

Initializing Mockito @Mocks with JUnit @Rule

In this post I will show how one can implement custom JUnit @Rule.

As an example let’s take Mockito and implement custom rule which will initialize Mocks in test class.

By default, Mockito provides the following methods of mock initialization:

  1. Using Mockito.mock

    Initialize mocks with Mockito.mock:

    public void FooTest {
    
        private Foo foo;
    
        @Before
        public void setUp() {
            FooDependency dep = Mockito.mock(FooDependency.class);
            foo = new Foo(dep);
        }
    }
    

    This is the simplest case.

  2. Using MockitoAnnotations. Initialize mocks with MockitoAnnotations:

    public void FooTest {
    
        private Foo foo;
    
        @Mock
        private FooDependency dep;
    
        @Before
        public void setUp() {
            MockitoAnnotations.initMocks(this);
            foo = new Foo(dep);
        }
    }
    

    This method is useful when you have a lot of mocks to inject.

  3. Using MockitoJUnitRunner

    Initialize mocks with MockitoJUnitRunner:

    @RunWith(MockitoJUnitRunner.class)
    public void FooTest {
    
        private Foo foo;
    
        @Mock
        private FooDependency dep;
    
        @Before
        public void setUp() {
            foo = new Foo(dep);
        }
    }
    

I want to show you another option, by using custom JUnit @Rule.

First, we need to implement TestRule interface which allows to implement custom behaviour during test execution:

MockitoInitializerRule:

public class MockitoInitializerRule implements TestRule {
    private Object test;

    public MockitoInitializerRule(Object test) {
        this.test = test;
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new MockitInitilizationStatement(base, test);
    }
}

We need to pass current test class instance to the rule, so it will be possible inject mocks into class instance. Actual implementation of our rule will go to new class - subclass of Statement:

MockitInitilizationStatement:

public class MockitInitilizationStatement extends Statement {
    private final Statement base;
    private Object test;

    MockitInitilizationStatement(Statement base, Object test) {
        this.base = base;
        this.test = test;
    }

    @Override
    public void evaluate() throws Throwable {
        MockitoAnnotations.initMocks(test);
        base.evaluate();
    }
}

What we do is basically initialize mocks in the test class and then proceed with the test method execution.

Now, let’s take a look at the usage of newly created Rule:

Example usage of MockitoInitializerRule:

public void FooTest {
    
    private Foo foo;

    @Mock
    private FooDependency dep;

    @Rule
    public TestRule mockitoInitializerRule = new MockitoInitializerRule(this);

    @Before
    public void setUp() {
        foo = new Foo(dep);
    }
}

Comparing to variant with MockitoJUnitRunner this one provides ability to use custom Runner, i.e. we can continue to use SpringJUnit4ClassRunner