Skip to content
Chapter 17 · JUnit 5 & Mockito

@Mock as a Constructor or Method Parameter ​

The previous chapter used @Mock and @InjectMocks on fields:

java
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Mock
    PaymentGateway gateway;

    @Mock
    OrderRepository repo;

    @InjectMocks
    OrderService service;

    @Test
    void placeOrder_success() {
        when(gateway.charge(100)).thenReturn(true);
        assertTrue(service.placeOrder(100));
        verify(repo).save();
    }
}

MockitoExtension uses BeforeEachCallback to create the mocks and AfterEachCallback to clean up. But it implements a third interface:

java
public class MockitoExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver

Why ParameterResolver ​

Recall from the extensions chapter: when JUnit calls a method or constructor with parameters, it asks every registered ParameterResolver whether it supports each parameter (supportsParameter) and, if so, to supply the value (resolveParameter).

MockitoExtension supports parameters annotated with @Mock and resolves each one by creating a mock of the parameter's type. So @Mock works on constructor and method parameters too, wherever JUnit resolves parameters.

Constructor parameters ​

java
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    private final PaymentGateway gateway;
    private final OrderRepository repo;
    private final OrderService service;

    OrderServiceTest(@Mock PaymentGateway gateway, @Mock OrderRepository repo) {
        this.gateway = gateway;
        this.repo = repo;
        this.service = new OrderService(gateway, repo);
    }

    @Test
    void placeOrder_success() {
        when(gateway.charge(100)).thenReturn(true);

        boolean result = service.placeOrder(100);

        assertTrue(result);
        verify(repo).save();
    }
}

When JUnit creates the test instance, it resolves the two constructor parameters through MockitoExtension, which returns a mock for each.

Pros

  • Clean, in the same constructor-injection style as production code.
  • The fields can be final.

Cons

  • Only safe with the default PER_METHOD lifecycle. The mocks are created when the test instance is created. With PER_CLASS there is one instance, so all tests share the same mocks, and stubs and call history leak:

    java
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    @ExtendWith(MockitoExtension.class)
    class OrderServiceTest {
        final PaymentGateway gateway;
    
        OrderServiceTest(@Mock PaymentGateway gateway) { this.gateway = gateway; }
    
        @Test void a() { gateway.charge(1); verify(gateway).charge(1); }   // passes
        @Test void b() { gateway.charge(1); verify(gateway).charge(1); }   // FAILS: "But was 2 times"
    }

    @Mock fields do not have this problem: MockitoExtension recreates them before every test, even with PER_CLASS.

  • You build the object under test yourself (new OrderService(gateway, repo)), which is usually the clearest choice anyway. @InjectMocks would still work here, because Mockito also injects mocks it finds in the test's fields, but mixing the two styles makes a test harder to follow.

Test method parameters ​

java
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Test
    void placeOrder_success(@Mock PaymentGateway gateway, @Mock OrderRepository repo) {
        OrderService service = new OrderService(gateway, repo);

        when(gateway.charge(100)).thenReturn(true);

        boolean result = service.placeOrder(100);

        assertTrue(result);
        verify(repo).save();
    }
}

The mocks exist only for this test method. That is fully isolated, but every test has to declare its own mocks and build its own object under test: repetitive when a class has many tests. It suits a mock that only one or two tests need.

Which to use ​

StyleMocks liveWatch out for
@Mock fields (+ @InjectMocks)recreated before each test@InjectMocks injection rules
@Mock constructor parametersas long as the test instancePER_CLASS lifecycle shares them
@Mock method parametersone test methodrepetition across tests

All three are correct. With constructor parameters, keep the default per-method lifecycle.

Next: With the mocks in place, the last two chapters cover what you do with them. Chapter 18 covers every way to stub: return values, exceptions, void methods, argument matchers and dynamic answers.

Check yourself ​

  1. Which three JUnit extension interfaces does MockitoExtension implement, and what is each for?
  2. Why can @Mock be used on a test constructor's parameters?
  3. Give two benefits of receiving mocks through the constructor.
  4. Why are constructor-parameter mocks risky with @TestInstance(PER_CLASS), and why are @Mock fields not?
  5. When are method-parameter mocks a good fit, and what is their drawback?
Answers
  1. BeforeEachCallback (create mocks, handle @InjectMocks), AfterEachCallback (finish the session, release state, check stubs), ParameterResolver (supply @Mock parameters).
  2. JUnit resolves constructor parameters through registered ParameterResolvers, and MockitoExtension supports parameters annotated @Mock.
  3. Clean constructor-injection style; the fields can be final.
  4. The constructor runs once per test instance; with PER_CLASS that is once for all tests, so the mocks and their history are shared. @Mock fields are recreated by the extension before every test.
  5. When only one or a few tests need a mock; the drawback is repeating the mocks and setup in every test.