Using Mockito With JUnit 5

Testing

In this article, we will learn how to use the Mockito mocking framework with JUnit 5. We will learn a test framework independent way, and how to use the Mockito JUnit 5 extension.

Manual Initialization

Before doing anything else, we have to add the Mockito dependency.

dependencies {
    testImplementation('org.mockito:mockito-core:3.12.4')
}

If we just want to create a mock to be injected into another object, the simplest way is to call the Mockito.mock() method. The method takes the class of the object to be instantiated as a parameter.

class MockitoManualTest {

    private OrderRepository orderRepository;
    private OrderService orderService;

    @BeforeEach
    void initService() {
        orderRepository = mock(OrderRepository.class);
        orderService = new OrderService(orderRepository);
    }

    @Test
    void createOrderSetsTheCreationDate() {
        Order order = new Order();
        when(orderRepository.save(any(Order.class))).then(returnsFirstArg());

        Order savedOrder = orderService.create(order);

        assertNotNull(savedOrder.getCreationDate());
    }
}

Manual initialization can be a legit solution if we don’t have many mocks.

Pros:

Cons:

Annotation Based Initialization

A declarative alternative to calling the Mockito.mock() method is to annotate a field as a mock with the @Mock annotation. We have to call a particular method to initialize the annotated objects.

In Mockito 2 there is a MockitoAnnotations.initMocks() method, which is deprecated and replaced with MockitoAnnotations.openMocks() in Mockito 3. The MockitoAnnotations.openMocks() method returns an instance of AutoClosable which can be used to close the resource after the test.

public class MockitoAnnotationTest {

    @Mock
    private OrderRepository orderRepository;
    private AutoCloseable closeable;
    private OrderService orderService;

    @BeforeEach
    void initService() {
        closeable = MockitoAnnotations.openMocks(this);
        orderService = new OrderService(orderRepository);
    }

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

    @Test
    void createOrderSetsTheCreationDate() {
        Order order = new Order();
        when(orderRepository.save(any(Order.class))).then(returnsFirstArg());

        Order savedOrder = orderService.create(order);

        assertNotNull(savedOrder.getCreationDate());
    }
}

The MockitoAnnotations.openMocks(this) call tells Mockito to scan this test class instance for any fields annotated with the @Mock annotation and initialize those fields as mocks.

Pros:

Cons:

Automatic Mock Injection

We can also tell Mockito to inject mocks automatically to a field annotated with @InjectMocks.

When MockitoAnnotations.openMocks() is called, Mockito will:

Using @InjectMocks is the same as we did when instantiating an instance manually, but now automatic.

public class MockitoInjectMocksTests {

    @Mock
    private OrderRepository orderRepository;
    private AutoCloseable closeable;
    @InjectMocks
    private OrderService orderService;

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

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

    @Test
    void createOrderSetsTheCreationDate() {
        Order order = new Order();
        when(orderRepository.save(any(Order.class))).then(returnsFirstArg());

        Order savedOrder = orderService.create(order);

        assertNotNull(savedOrder.getCreationDate());
    }
}

Mockito will first try to inject mocks by constructor injection, followed by setter injection, or field injection.

Pros:

Cons:

Warning

It is not recommended to use field or setter injection. Using constructor injection, we can be 100% sure no one instantiates the class without injecting its dependencies.

Mockito JUnit 5 Extension

There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.

To be able to use the extension we have to first add the dependency to it.

dependencies {
    testImplementation('org.mockito:mockito-junit-jupiter:3.12.4')
}

Now we can apply the extension and get rid of the MockitoAnnotations.openMocks() method call.

@ExtendWith(MockitoExtension.class)
public class MockitoExtensionTest {

    @Mock
    private OrderRepository orderRepository;
    private OrderService orderService;

    @BeforeEach
    void initService() {
        orderService = new OrderService(orderRepository);
    }

    @Test
    void createOrderSetsTheCreationDate() {
        Order order = new Order();
        when(orderRepository.save(any(Order.class))).then(returnsFirstArg());

        Order savedOrder = orderService.create(order);

        assertNotNull(savedOrder.getCreationDate());
    }
}

Note that we can use the @InjectMocks annotation with the MockitoExtension as well to simplify the setup further.

@ExtendWith(MockitoExtension.class)
public class MockitoExtensionInjectMocksTest {

    @Mock
    private OrderRepository orderRepository;
    @InjectMocks
    private OrderService orderService;

    @Test
    void createOrderSetsTheCreationDate() {
        when(orderRepository.save(any(Order.class))).then(returnsFirstArg());

        Order order = new Order();

        Order savedOrder = orderService.create(order);

        assertNotNull(savedOrder.getCreationDate());
    }
}

If we do not want to share mock variables across all test cases, we can also inject mock objects to method parameters.

    @Test
    void createOrderSetsTheCreationDate(@Mock OrderRepository orderRepository) {
        OrderService orderService = new OrderService(orderRepository);
        when(orderRepository.save(any(Order.class))).then(returnsFirstArg());

        Order order = new Order();

        Order savedOrder = orderService.create(order);

        assertNotNull(savedOrder.getCreationDate());
    }

Injecting mocks to method parameters works both on the lifecycle methods and on the test methods themselves.

Pros:

Cons:

Summary

There are three different ways of using Mockito with JUnit 5. First two approaches work independently of the used framework, while the third one utilizes the Mockito JUnit 5 extension.

Mocks can be created and initialized by:

The example code for this guide can be found on GitHub.

This article is part of the JUnit 5 Tutorial series

  1. 1. Getting Started with JUnit 5: Writing Your First Test
  2. 2. JUnit 5 Assertions: Verifying Test Results
  3. 3. JUnit 5 Test Lifecycle: Before and After Annotations
  4. 4. JUnit 5 Nested Tests: Grouping Related Tests Together
  5. 5. A More Practical Guide to JUnit 5 Parameterized Tests
  6. 6. Using Mockito With JUnit 5
  7. 7. Migrating From JUnit 4 to JUnit 5: A Definitive Guide
junit-5