Appearance
@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:
- Manually, with
Mockito.mock()andMockito.spy(). - Annotations without the extension:
@Mock,@Spy,@InjectMocksplusMockitoAnnotations.openMocks(). - Annotations with
MockitoExtension: the recommended, industry-standard way.
All three use the same machinery described in the architecture chapter.
Dependencies
| Artifact | Contains | Needed for |
|---|---|---|
mockito-core | mock, spy, when, verify, the annotations, openMocks | ways 1 and 2 |
mockito-junit-jupiter | MockitoExtension (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.
| Where | Safe? | Why |
|---|---|---|
@BeforeEach | yes | a fresh mock for every test; nothing to reset or clean up |
@BeforeAll | no | one mock shared by all tests: stubs and call history leak between them |
field initializer, default PER_METHOD lifecycle | yes | a new test instance, so new fields, for every test |
field initializer, PER_CLASS lifecycle | no | one 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:
- Reflection scan: find the fields annotated
@Mock,@Spyand@InjectMocks. - Create mocks and spies:
gateway = Mockito.mock(PaymentGateway.class),repo = Mockito.mock(OrderRepository.class). - Handle
@InjectMocks: create the real object and put the mocks into it; hereservice = new OrderService(gateway, repo). - 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
AutoCloseablefield,openMocksin@BeforeEach,close()in@AfterEach. - Easy to forget
close(). - Manual wiring into the JUnit lifecycle: someone may put
openMocksin@BeforeAll, and then all tests share the same mocks.
3. Annotations with MockitoExtension (recommended)
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 whatopenMocksdoes: creates@Mock/@Spyfields and handles@InjectMocks.afterEach: finishes the session, which releases the state likeclose(), and checks for problems such as unused stubs (see the stubbing chapter).ParameterResolver: lets you use@Mockon 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:
- Constructor injection
- Setter injection
- 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:
- Pick the constructor with the most parameters.
- For each parameter, use a mock of that type from the test class.
- For an object parameter with no mock, pass
null. Mockito never creates a mock you did not declare. - For a primitive parameter (
int,boolean, ...), Mockito does not guess a value; the constructor cannot be used. - 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 constructorThe 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), notsalesRepo(...)oraddSalesRepo(...)) 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(andstatic) 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;- Constructor injection: the 3-parameter constructor is picked;
int varcannot be resolved, so fall back:new OrderService(). - Setter injection:
gatewayhassetGateway, called with thePaymentGatewaymock. - Field injection:
repoandsalesRepohave 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
- Which artifact contains
MockitoExtension, and do you also needmockito-core? - Why is creating a mock in
@BeforeAllunsafe, and when is a field initializer safe? - What do
@Mockfields hold beforeopenMocks(this)runs? - What are the four steps of
openMocks, and why must you callclose()on its result? - What does
MockitoExtensiondo before and after each test? - In which order does
@InjectMockstry its strategies? - Which constructor does constructor injection pick, and what does it pass for an object type with no mock? For an
int? - The biggest constructor has an
intparameter and there is no no-argument constructor. What happens? - Can field injection set a private field? A final field?
- Name two conditions a setter must meet to be used.
Answers
mockito-junit-jupiter. No: it bringsmockito-corewith it.- One mock is shared by all tests, so stubs and call history leak between them. A field initializer is safe with the default
PER_METHODlifecycle (a new instance per test), not withPER_CLASS. null: the annotation is only metadata.- Scan the annotated fields; create the mocks and spies; create the
@InjectMocksobject and inject them; keep internal state.close()releases that state, which could otherwise affect later tests on the same thread and waste memory. - 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. - Constructor, then setter, then field injection.
- The one with the most parameters;
nullfor an unmocked object; it never guesses a primitive, so that constructor is abandoned. - Mockito falls back to the no-argument constructor, finds none, and fails with "has no default constructor".
- Private: yes, by reflection. Final: no.
- JavaBean name (
set+ field name) and exactly one parameter.