Skip to content
Chapter 16 · JUnit 5 & Mockito

@Mock, @Spy and @InjectMocks ​

Chapters 14 and 15 created mocks by hand with Mockito.mock(). Real test classes have several dependencies, and creating and wiring them by hand gets repetitive.

There are three ways to create mocks and spies and connect them to JUnit:

  1. Manually, with Mockito.mock() and Mockito.spy().
  2. Annotations without the extension: @Mock, @Spy, @InjectMocks plus MockitoAnnotations.openMocks().
  3. Annotations with MockitoExtension: the recommended, industry-standard way.

All three use the same machinery described in the architecture chapter.

Dependencies ​

ArtifactContainsNeeded for
mockito-coremock, spy, when, verify, the annotations, openMocksways 1 and 2
mockito-junit-jupiterMockitoExtension (and brings mockito-core with it)way 3
xml
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <scope>test</scope>
</dependency>

In a Spring Boot project, spring-boot-starter-test already includes both, with managed versions; add nothing.

The Java agent. On recent JDKs, Mockito prints "Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK." The inline mock maker needs a Java agent, and the JDK is phasing out agents that attach themselves at run time. Mockito's documented fix is to pass mockito-core as an agent to the test JVM:

xml
<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <goals><goal>properties</goal></goals>   <!-- defines ${org.mockito:mockito-core:jar} -->
        </execution>
    </executions>
</plugin>
<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>-javaagent:${org.mockito:mockito-core:jar}</argLine>
    </configuration>
</plugin>

If another plugin (such as JaCoCo) already sets argLine, write @{argLine} -javaagent:... to keep its value. Without such a plugin, @{argLine} stays undefined and the test JVM fails to start.

1. Manually ​

java
Calculator calculator = Mockito.mock(Calculator.class);
Calculator spyCalc    = Mockito.spy(new Calculator());

Where you create them matters, because a mock remembers its stubs and every call made on it.

WhereSafe?Why
@BeforeEachyesa fresh mock for every test; nothing to reset or clean up
@BeforeAllnoone mock shared by all tests: stubs and call history leak between them
field initializer, default PER_METHOD lifecycleyesa new test instance, so new fields, for every test
field initializer, PER_CLASS lifecyclenoone test instance, one mock for all tests
java
@BeforeEach
void setup() {
    calculator = Mockito.mock(Calculator.class);
}

The leak with PER_CLASS:

java
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CalculatorTest {

    Calculator calculator = Mockito.mock(Calculator.class);

    @Test
    void test1() {
        calculator.multiply(10, 2);
        verify(calculator).multiply(10, 2);   // passes
    }

    @Test
    void test2() {
        calculator.multiply(10, 2);
        verify(calculator).multiply(10, 2);   // FAILS: "Wanted 1 time ... But was 2 times"
    }
}

The mock still holds test1's call. (Test order is not guaranteed either; with a different order the other test fails.)

2. Annotations without the extension ​

The class under test and its dependencies:

java
public class OrderService {

    private final PaymentGateway gateway;
    private final OrderRepository repo;

    public OrderService(PaymentGateway gateway, OrderRepository repo) {
        this.gateway = gateway;
        this.repo = repo;
    }

    public boolean placeOrder(int amount) { ... }
}

public interface PaymentGateway { boolean charge(int amount); }
public interface OrderRepository { void save(); }

Manually you would write Mockito.mock(PaymentGateway.class), Mockito.mock(OrderRepository.class), then new OrderService(gatewayMock, repoMock). The annotations do all of this:

  • @Mock: create a mock for this field.
  • @Spy: create a spy for this field.
  • @InjectMocks: create a real object of this field's type and inject the mocks and spies into it.
java
class OrderServiceTest {

    AutoCloseable closeable;

    @Mock
    PaymentGateway gateway;      // only metadata for now: gateway is null

    @Mock
    OrderRepository repo;        // null

    @InjectMocks
    OrderService service;        // null

    @BeforeEach
    void init() {
        closeable = MockitoAnnotations.openMocks(this);
    }

    @AfterEach
    void cleanup() throws Exception {
        closeable.close();
    }

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

        boolean result = service.placeOrder(100);

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

The annotations alone do nothing: without openMocks, the fields stay null. openMocks(this) does the work:

  1. Reflection scan: find the fields annotated @Mock, @Spy and @InjectMocks.
  2. Create mocks and spies: gateway = Mockito.mock(PaymentGateway.class), repo = Mockito.mock(OrderRepository.class).
  3. Handle @InjectMocks: create the real object and put the mocks into it; here service = new OrderService(gateway, repo).
  4. Keep state: Mockito records what it created and holds some state per thread.

It returns an AutoCloseable; close() releases that state. Tests may run on pooled threads, and state left on a thread can affect the next test that thread runs and wastes memory. So always keep the reference and close it in @AfterEach.

Drawbacks of this way:

  • Boilerplate in every test class: the AutoCloseable field, openMocks in @BeforeEach, close() in @AfterEach.
  • Easy to forget close().
  • Manual wiring into the JUnit lifecycle: someone may put openMocks in @BeforeAll, and then all tests share the same mocks.
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);

        boolean result = service.placeOrder(100);

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

No openMocks, no close(), no lifecycle wiring. MockitoExtension is a JUnit extension (see the extensions chapter) that implements BeforeEachCallback, AfterEachCallback and ParameterResolver:

  • beforeEach: starts a Mockito session for the test instance, which does what openMocks does: creates @Mock/@Spy fields and handles @InjectMocks.
  • afterEach: finishes the session, which releases the state like close(), and checks for problems such as unused stubs (see the stubbing chapter).
  • ParameterResolver: lets you use @Mock on parameters (next chapter).

Because it runs before each test, mocks are fresh for every test even with the PER_CLASS lifecycle.

How @InjectMocks injects ​

Mockito tries three strategies, in this priority order:

  1. Constructor injection
  2. Setter injection
  3. Field injection

Mocks are matched to parameters and fields by type (the name is only used to choose when several mocks have the same type).

Constructor injection ​

Rules:

  1. Pick the constructor with the most parameters.
  2. For each parameter, use a mock of that type from the test class.
  3. For an object parameter with no mock, pass null. Mockito never creates a mock you did not declare.
  4. For a primitive parameter (int, boolean, ...), Mockito does not guess a value; the constructor cannot be used.
  5. If the chosen constructor cannot be used, fall back to the no-argument constructor, then try setter and field injection.

If the constructor works, injection stops there: setters and fields are not touched.

Case 1: one constructor, exact match. OrderService(PaymentGateway, OrderRepository) with both mocked: service = new OrderService(gateway, repo).

Case 2: several constructors, one dependency not mocked.

java
public OrderService(PaymentGateway gateway, OrderRepository repo) { ... }
public OrderService(PaymentGateway gateway, OrderRepository repo, SalesRepository salesRepo) { ... }

With mocks for PaymentGateway and OrderRepository only: the 3-parameter constructor is picked, SalesRepository has no mock, so service = new OrderService(gateway, repo, null).

Case 3: a primitive parameter.

java
public OrderService(PaymentGateway gateway, OrderRepository repo) { ... }
public OrderService(PaymentGateway gateway, OrderRepository repo, int var) { ... }

The 3-parameter constructor is picked; int var cannot be resolved, so Mockito falls back to the no-argument constructor. There is none, so the test fails:

text
Cannot instantiate @InjectMocks field named 'service'! Cause: the type 'OrderService' has no default constructor

The 2-parameter constructor is not tried.

Setter and field injection ​

These run only when the object was created with the no-argument constructor. Then, for each field of the object:

  • Setter injection first. The setter must follow the JavaBean naming convention (setSalesRepo(SalesRepository salesRepo), not salesRepo(...) or addSalesRepo(...)) and take exactly one argument.
  • Field injection for fields with no usable setter: Mockito sets the field directly by reflection, even if it is private.
  • final (and static) fields are never injected, by setter or field.
java
public class OrderService {

    private PaymentGateway gateway;
    private OrderRepository repo;
    private SalesRepository salesRepo;

    public OrderService() { }

    public OrderService(PaymentGateway gateway, OrderRepository repo, int var) { ... }

    public void setGateway(PaymentGateway gateway) { this.gateway = gateway; }
}
java
@Mock PaymentGateway gate;            // the name differs from the field: matching is by type
@Mock OrderRepository repo;
@Mock SalesRepository salesRepo;

@InjectMocks OrderService service;
  1. Constructor injection: the 3-parameter constructor is picked; int var cannot be resolved, so fall back: new OrderService().
  2. Setter injection: gateway has setGateway, called with the PaymentGateway mock.
  3. Field injection: repo and salesRepo have no setters, so they are set directly, though private.

A trap of rule 5: if the biggest constructor can be called (with null for unmocked objects), Mockito uses it and does not go on to setters or fields, even when other mocks are available for them.

If no strategy can inject a dependency, Mockito does not report an error: the field simply stays null. When injection surprises you, construct the object yourself in @BeforeEach; it is often clearer anyway.

Next: MockitoExtension implements a third extension interface, ParameterResolver. Chapter 17 shows what that allows: @Mock on constructor and test method parameters.

Check yourself ​

  1. Which artifact contains MockitoExtension, and do you also need mockito-core?
  2. Why is creating a mock in @BeforeAll unsafe, and when is a field initializer safe?
  3. What do @Mock fields hold before openMocks(this) runs?
  4. What are the four steps of openMocks, and why must you call close() on its result?
  5. What does MockitoExtension do before and after each test?
  6. In which order does @InjectMocks try its strategies?
  7. Which constructor does constructor injection pick, and what does it pass for an object type with no mock? For an int?
  8. The biggest constructor has an int parameter and there is no no-argument constructor. What happens?
  9. Can field injection set a private field? A final field?
  10. Name two conditions a setter must meet to be used.
Answers
  1. mockito-junit-jupiter. No: it brings mockito-core with it.
  2. One mock is shared by all tests, so stubs and call history leak between them. A field initializer is safe with the default PER_METHOD lifecycle (a new instance per test), not with PER_CLASS.
  3. null: the annotation is only metadata.
  4. Scan the annotated fields; create the mocks and spies; create the @InjectMocks object and inject them; keep internal state. close() releases that state, which could otherwise affect later tests on the same thread and waste memory.
  5. Before: start a Mockito session that creates the mocks and handles @InjectMocks. After: finish the session, releasing state and checking for problems such as unused stubs.
  6. Constructor, then setter, then field injection.
  7. The one with the most parameters; null for an unmocked object; it never guesses a primitive, so that constructor is abandoned.
  8. Mockito falls back to the no-argument constructor, finds none, and fails with "has no default constructor".
  9. Private: yes, by reflection. Final: no.
  10. JavaBean name (set + field name) and exactly one parameter.