Overview

Today, I will share with you three different ways to initialize mock objects in JUnit:

  • MockitoExtension
  • MockitoAnnotations#initMocks
  • Mockito#mock

I will share not only the source code, but also their advantage and inconvenience to let you better choose which approach is the best for you. This article is written with JUnit 5.6.2 and Mockito 2.28.2.

Prerequisites

To use the core features of Mockito 2, you need to import the following dependency into your Maven project:

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>2.28.2</version>
  <scope>test</scope>
</dependency>

MockitoExtension

In JUnit 4, Mock objects can be created using Mockito JUnit Runner. In JUnit 5, “Runner”, “TestRule”, and “MethodRule” extension points, available in JUnit 4, are replaced by the Extension API. You can register the Mockito extension via @ExtendWith. The Mockito extension:

  • Initializes mocks annotated with @Mock, so that explicit usage of MockitoAnnotations#initMocks(Object) is not necessary. Mocks are initialized before each test method.
  • Validates framework usage after each test method. See the Javadoc of Mockito#validateMockitoUsage()

But before doing so, you need to add an additional dependency to your project:

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-junit-jupiter</artifactId>
  <version>2.28.2</version>
  <scope>test</scope>
</dependency>

Here’s an example of how you can use it:

@ExtendWith(MockitoExtension.class)
class BookReaderAnnotationWithExtensionTest {

  @Mock private Book mockedBook;

  private BookReader reader;

  @BeforeEach
  void setUp() {
    reader = new BookReader(mockedBook);
  }

  @Test
  void testGetContent() {
    Mockito.when(mockedBook.getContent()).thenReturn("Mockito");
    assertEquals("Mockito", reader.getContent());
  }
}

In JUnit 4, the annotation @RunWith can only be used once. It was not a repeatable annotation. Using @MockitoJUnitRunner means you cannot use other runners anymore. However, In JUnit 5, the annotation @ExtendWith is repeatable, so you can use it without worrying about the exclusivity.

After each test case, Mockito extension validates the framework state to detect invalid use of Mockito. For example, if you disable the assertion from method testGetContent, you will see the test failed with the following exception:

“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 …testGetContent(BookReaderAnnotationWithExtensionTest.java:38))

Please remove unnecessary stubbings or use ‘lenient’ strictness. More info: javadoc for UnnecessaryStubbingException class.”

Pros:

  • No need for explicit MockitoAnnotations#initMocks(Object)
  • Validates framework usage after each test method
  • Declarative thanks to @Mock annotation
  • Easy to create mocks
  • Easy to read
  • Compatible with other extensions because @ExtendWith is repeatable.

Cons:

  • Additional dependency on org.mockito:mockito-junit-jupiter

MockitoAnnotations.initMocks

Mock objects can be initialized using Mockito annotation @Mock and MockitoAnnotations#initMocks(Object).

// you don't need: @ExtendWith(MockitoExtension.class)
class BookReaderAnnotationWithSetupTest {

  private BookReader reader;

  @Mock private Book mockedBook;

  @BeforeEach
  void setUp() {
    MockitoAnnotations.initMocks(this);
    reader = new BookReader(mockedBook);
  }

  @Test
  void testPrintContent() {
    mockedBook.printContent();
    Mockito.verify(mockedBook).printContent();
  }

  @Test
  void testGetContent() {
    Mockito.when(mockedBook.getContent()).thenReturn("Mockito");
    assertEquals("Mockito", reader.getContent());
  }
}

Pros:

  • Declarative thanks to @Mock annotation
  • Easy to read
  • Easy to create mocks

Cons:

  • Missing framework-usage validation after each test

Mockito.mock

Create mock object of given class or interface using Mockito#mock(Class<T> classToMock) or its overloaded methods.

class BookReaderClassicMockTest {

  private BookReader reader;
  private Book mockedBook;

  @BeforeEach
  void setUp() {
    mockedBook = Mockito.mock(Book.class);
    reader = new BookReader(mockedBook);
  }

  @Test
  void testPrintContent() {
    mockedBook.printContent();
    Mockito.verify(mockedBook).printContent();
  }

  @Test
  void testGetContent() {
    Mockito.when(mockedBook.getContent()).thenReturn("Mockito");
    assertEquals("Mockito", reader.getContent());
  }
}

Pros:

  • More control on the mock you need to create
  • No need to share mock variables across all test cases as class-variables

Cons:

  • More verbose
  • Less declarative
  • Missing framework-usage validation after each test

Going Further

How to go further from here?

Conclusion

Today, I shared 3 different ways to initialize mock objects in JUnit 5, using Mockito Extension (MockitoExtension), Mockito Annotations (MockitoAnnotation#initMocks), and the traditional Mockito#mock. The source code of the examples above are available on GitHub mincong-h/java-examples. Interested to know more? You can subscribe to the feed of my blog, follow me on Twitter or GitHub. Hope you enjoy this article, see you the next time!

References