Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

@Mock and @InjectMocks with MockitoExtension

Creating mocks with mock(...) and passing them to the constructor by hand is fine for two dependencies. With more, the setup grows. Mockito can do it for you: fields marked @Mock become mocks, and the field marked @InjectMocks gets an object of the class under test with those mocks passed in. The JUnit extension MockitoExtension connects this to the test lifecycle.

The annotations

// src/test/java/com/example/blog/PostServiceAnnotationsTest.java
package com.example.blog;
 
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
 
import java.util.Optional;
 
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
 
@ExtendWith(MockitoExtension.class)
class PostServiceAnnotationsTest {
 
    @Mock
    PostRepository repository;
 
    @Mock
    Notifier notifier;
 
    @InjectMocks
    PostService service;
 
    @Test
    void publish() {
        when(repository.findById(1L))
                .thenReturn(Optional.of(new Post(1L, "Hello", "anna", false)));
 
        Post post = service.publish(1L);
 
        assertTrue(post.published());
        verify(notifier).send("anna", "Your post \"Hello\" is published");
    }
}
PartWhat it does
@ExtendWith(MockitoExtension.class)Before each test, creates the mocks and fills the fields
@MockThe field becomes a new mock of its type
@InjectMocksCreates PostService and passes the mocks to the constructor by type
@CaptorThe field becomes an ArgumentCaptor: @Captor ArgumentCaptor<Post> captor;

@InjectMocks picks the constructor with the most parameters. If there is no suitable constructor, it tries setters and fields. Constructor injection is the most reliable: the service cannot exist without its dependencies.

Strict stubbing

MockitoExtension is strict: it fails a test that stubs something the code never uses. Such a when is usually a leftover from copying or a sign that the test checks something other than it thinks:

// src/test/java/com/example/blog/PostServiceAnnotationsTest.java
@Test
void publishedIsEmpty() {
    when(repository.findById(1L))
            .thenReturn(Optional.of(new Post(1L, "Hello", "anna", false)));
    when(repository.findAll()).thenReturn(List.of());
 
    assertEquals(0, service.published().size());
}
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at com.example.blog.UnnecessaryTest.publishedIsEmpty(UnnecessaryTest.java:29)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.

published() calls only findAll(), so the stub of findById is unnecessary — delete it. In rare cases where a stub is shared by tests and not every test uses it, mark it lenient().when(...).

Common mistake

The annotations alone do nothing: without @ExtendWith(MockitoExtension.class) nobody creates the mocks, and the fields stay null:

[ERROR] com.example.blog.NoExtensionTest.publish -- Time elapsed: 0.050 s <<< ERROR!
java.lang.NullPointerException: Cannot invoke "com.example.blog.PostRepository.findById(long)" because "this.repository" is null
	at com.example.blog.NoExtensionTest.publish(NoExtensionTest.java:24)

A NullPointerException on a @Mock field almost always means a forgotten @ExtendWith. Add it to the class.

Thanks for reading!

Donate to the site — we work hard for you.