Guide to Initializing Mocks with Mockito Annotations and openMocks in JUnit 5

Explore how to efficiently initialize mocks using MockitoAnnotations.openMocks in JUnit 5. Learn key concepts, best practices, and common pitfalls.

Get Started free
How to Initialize Mocks with MockitoAnnotations.openMocks A Guide for JUnit 5
Home Guide Guide to Initializing Mocks with Mockito Annotations and openMocks in JUnit 5

Guide to Initializing Mocks with Mockito Annotations and openMocks in JUnit 5

Mockito is one of the most widely used Java frameworks for creating mock objects, allowing developers to isolate dependencies and verify interactions in unit tests.

Combined with JUnit, it enables efficient test-driven development (TDD) by simplifying test case construction through annotations and assertions.

This article explores how to initialize mock objects using MockitoAnnotations.openMocks in JUnit 5. It covers key Mockito annotations, various mock definitions, step-by-step examples, common pitfalls, and best practices for effective testing.

What is MockitoAnnotations.openMocks?

In version 3.4.0 of Mockito, MockitoAnnotations.openMocks provides a method for initializing mock objects, which can be inserted into test class fields.

The openMocks method took over from the deprecated MockitoAnnotations.initMocks method to boost support for JUnit 5 and enhance resource handling.

Syntax

AutoCloseable closeable = MockitoAnnotations.openMocks(this);
Copied

Explanation

  • Mock Initialization: With openMocks, the testing process automatically initializes all fields that use @Mock, @Spy, @Captor, or @InjectMocks annotations while scanning test class code.
  • Resource Management: During test execution, users receive an AutoCloseable object that enables automatic resource cleanup. The method needs an annotation of @AfterEach to execute its closure step.
  • Usage in JUnit 5: Developers typically use the @BeforeEach and @AfterEach methods alongside each other for mock preparation before each test and resource management operations after tests conclude.

Example Usage

import org.junit.jupiter.api.*;

import org.mockito.*;

import static org.mockito.Mockito.*;



class UserServiceTest {

    @Mock

    private UserRepository userRepository;



    @InjectMocks

    private UserService userService;



    private AutoCloseable closeable;



    @BeforeEach

    void setUp() {

        closeable = MockitoAnnotations.openMocks(this);

    }



    @AfterEach

    void tearDown() throws Exception {

        closeable.close();

    }



    @Test

    void testGetUser() {

        when(userRepository.findById(1L)).thenReturn(new User(1L, "John Doe"));

        User user = userService.getUser(1L);

        assertEquals("John Doe", user.getName());

    }

}
Copied

Note: Ensure that JUnit 5 and Mockito dependencies are present and that the imports are correct for proper mock initialization. Use @AfterEach to close AutoCloseable and prevent memory leaks. MockitoExtension.class simplifies mock setup by eliminating explicit initialization.

The Role of Mockito in JUnit Testing

As a Java-based open-source framework, Mockito enables users to develop unit tests by implementing mock object creation and management features.

Mockito improves the testing process via several important capabilities when combined with JUnit:

  • Unit Isolation: Mockito creates mock dependencies, allowing independent testing of specific units without external interference.
  • Behavior Simulation: Developers can define mock responses for different scenarios, simulating method return values or exceptions.
  • Interaction Verification: Ensures correct method calls, invocation counts, and parameter usage, validating expected behavior.
  • Test Automation Support: Integrates seamlessly with JUnit to automate mock creation, reducing boilerplate code and accelerating TDD adoption.

Understanding Mockito Annotations

The annotation library of Mockito serves to manage and create mock objects during unit test development.

Here are the explanations and demonstrations of the usage of these annotations, including their intended functions:

1. @Mock

The annotation creates a simulated version of a class or interface, enabling you to specify behavior rules without using real system components.

Example:

  import static org.mockito.Mockito.*;

  import org.junit.jupiter.api.Test;

  import org.mockito.Mock;

  import org.mockito.junit.jupiter.MockitoExtension;

  import org.junit.jupiter.api.extension.ExtendWith;



  @ExtendWith(MockitoExtension.class)

  public class MockExampleTest {



      @Mock

      private List<String> mockList;



      @Test

      public void testMock() {

          mockList.add("test");

          verify(mockList).add("test");

      }

  }
Copied

In this example, mockList is a mock List<String> instance. The test verifies that the add(“test”) method was called on mockList.

2. @Spy

Generates a spy of a genuine object to allow some mocking. You can pretend to employ particular techniques with spies while letting others apply their actual implementations.

Example:

 import static org.mockito.Mockito.*;

  import org.junit.jupiter.api.Test;

  import org.mockito.Spy;

  import org.mockito.junit.jupiter.MockitoExtension;

  import org.junit.jupiter.api.extension.ExtendWith;



  @ExtendWith(MockitoExtension.class)

  public class SpyExampleTest {



      @Spy

      private ArrayList<String> spyList = new ArrayList<>();



      @Test

      public void testSpy() {

          spyList.add("test");

          verify(spyList).add("test");

          assertEquals(1, spyList.size());



          doReturn(5).when(spyList).size();

          assertEquals(5, spyList.size());

      }

  }
Copied

Here, spyList is a spy of an ArrayList. The test adds an element, verifies the addition, and then mocks the size() method to return 5.

3. @InjectMocks

Automatically generates spy or dummy versions of the tested object. This lets the class under test get dependencies specified with @Mock or @Spy, facilitating testing.

Example:

  import static org.mockito.Mockito.*;

  import org.junit.jupiter.api.Test;

  import org.mockito.InjectMocks;

  import org.mockito.Mock;

  import org.mockito.junit.jupiter.MockitoExtension;

  import org.junit.jupiter.api.extension.ExtendWith;



  @ExtendWith(MockitoExtension.class)

  public class InjectMocksExampleTest {



      @Mock

      private Repository mockRepository;



      @InjectMocks

      private Service service;



      @Test

      public void testFetchData() {

          when(mockRepository.getData()).thenReturn("Mock Data");

          String result = service.fetchData();

          assertEquals("Mock Data", result);

      }

  }
Copied

In this scenario, mockRepository is injected into the service instance, allowing the test to define mock behaviors and verify outcomes.

4. @Captor

Generates an ArgumentCaptor class to record method arguments for additional assertions, hence allowing confirmation of the passed arguments for mocked methods.

Example:

  import static org.mockito.Mockito.*;

  import org.junit.jupiter.api.Test;

  import org.mockito.Captor;

  import org.mockito.Mock;

  import org.mockito.junit.jupiter.MockitoExtension;

  import org.junit.jupiter.api.extension.ExtendWith;

  import org.mockito.ArgumentCaptor;



  @ExtendWith(MockitoExtension.class)

  public class CaptorExampleTest {



      @Mock

      private List<String> mockList;



      @Captor

      private ArgumentCaptor<String> captor;



      @Test

      public void testCaptor() {

          mockList.add("test");

          verify(mockList).add(captor.capture());

          assertEquals("test", captor.getValue());

      }

  }
Copied

Here, the captor captures the argument passed to the add method, allowing the test to assert that “test” was added to the list.

5. @ExtendWith(MockitoExtension.class)

Combines Mockito with JUnit 5 to automatically initiate mocks, spies, and other Mockito annotations without explicit configuration.

Example:

  import org.junit.jupiter.api.Test;

  import org.mockito.Mock;

  import org.mockito.junit.jupiter.MockitoExtension;

  import org.junit.jupiter.api.extension.ExtendWith;



  @ExtendWith(MockitoExtension.class)

  public class ExtendWithExampleTest {



      @Mock

      private List<String> mockList;



      @Test

      public void testExtension() {

          mockList.add("test");

          verify(mockList).add("test");

      }

  }
Copied

Mockito manages the initializing of annotated fields by annotating the class with @ExtendWith(MockitoExtension.class), optimizing the test setup procedure.

These annotations improve test readability and maintainability by lowering boilerplate codes and enabling the administration of simulated objects.

Step-by-Step Guide to Using MockitoAnnotations.openMocks in JUnit 5

To effectively utilize MockitoAnnotations.openMocks in JUnit 5 for initializing mocks, follow the steps outlined below:

Prerequisites:

  • JUnit 5 Dependency: Ensure that your project includes the JUnit 5 library.
  • Mockito Dependency: Include the Mockito library in your project.

Step 1: Add Dependencies

Incorporate the necessary dependencies into your project’s build configuration.

For Maven:

<dependency>

    <groupId>org.junit.jupiter</groupId>

    <artifactId>junit-jupiter-api</artifactId>

    <version>5.10.0</version>

    <scope>test</scope>

</dependency>

<dependency>

    <groupId>org.mockito</groupId>

    <artifactId>mockito-core</artifactId>

    <version>5.3.1</version>

    <scope>test</scope>

</dependency>
Copied

For Gradle:

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'

testImplementation 'org.mockito:mockito-core:5.3.1'
Copied

Step 2: Initialize Mocks in the Test Class

Utilize MockitoAnnotations.openMocks(this) within a @BeforeEach method to initialize mocks before each test and ensure proper resource management by closing them in an @AfterEach method.

import org.junit.jupiter.api.*;

import org.mockito.*;

import static org.mockito.Mockito.*;



class BusinessLogicTest {

    @Mock

    private DataService dataService;



    @InjectMocks

    private BusinessLogic businessLogic;



    private AutoCloseable closeable;



    @BeforeEach

    void setUp() {

        closeable = MockitoAnnotations.openMocks(this);

    }



    @AfterEach

    void tearDown() throws Exception {

        closeable.close();

    }



    @Test

    void testProcessData() {

        when(dataService.getData()).thenReturn("Mocked Response");

        String result = businessLogic.processData();

        assertEquals("Mocked Response", result);

    }

}
Copied

Explanation:

  • @Mock: Creates a mock instance of DataService.
  • @InjectMocks: Injects the mock dataService into the businessLogic instance.
  • setUp(): Initializes the mocks before each test by calling MockitoAnnotations.openMocks(this).
  • tearDown(): Closes the AutoCloseable resource after each test to prevent memory leaks.

Output Example:

Assuming DataService and BusinessLogic are defined as follows:

class DataService {

    String getData() {

        // Original implementation

        return "Real Data";

    }

}




class BusinessLogic {

    private final DataService dataService;




    BusinessLogic(DataService dataService) {

        this.dataService = dataService;

    }




    String processData() {

        return dataService.getData();

    }

}
Copied

When running the testProcessData method, the output will be:

org.opentest4j.AssertionFailedError: 

Expected :Mocked Response

Actual   :Mocked Response
Copied

This indicates that the mock was successfully injected, and the processData method returned the mocked response as expected.

Alternative Approach: Using MockitoExtension

Mockito offers a JUnit 5 module that automates the mock setup process as a substitute for manual initializing. Mockito will automatically handle mocks by annotating the test class with @ExtendWith(MockitoExtension.class), handling their generation and injection.

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 static org.mockito.Mockito.when;

import static org.junit.jupiter.api.Assertions.assertEquals;



@ExtendWith(MockitoExtension.class)

class BusinessLogicTest {

    @Mock

    private DataService dataService;



    @InjectMocks

    private BusinessLogic businessLogic;



    @Test

    void testProcessData() {

        when(dataService.getData()).thenReturn("Mocked Response");

        String result = businessLogic.processData();

        assertEquals("Mocked Response", result);

    }

}
Copied

In this setup, the @ExtendWith(MockitoExtension.class) annotation ensures that Mockito processes the annotations and injects the necessary mock instances, eliminating the need for explicit initialization and resource management.

BrowserStack Automate Banner

Difference Between MockitoAnnotations.initMocks vs MockitoAnnotations.openMocks

In Mockito, the transition from MockitoAnnotations.initMocks() to MockitoAnnotations.openMocks() reflects an evolution in the framework to enhance integration with JUnit 5 and improve resource management.

Here’s a detailed comparison between the two methods:

FeatureinitMocks()openMocks()
JUnit CompatibilityCompatible with JUnit 4 and JUnit 5.Specifically designed for JUnit 5 and later versions.
Deprecation StatusDeprecated as of Mockito 3.4.0.Introduced in Mockito 3.4.0 as the preferred method.
Resource ManagementDoes not support AutoCloseable; manual resource management is required.Returns an AutoCloseable instance, facilitating automatic resource management.
Usage PatternRequires explicit initialization, typically in a @BeforeEach method.Encourages initialization in a @BeforeEach method with automatic cleanup in an @AfterEach method.

Importance of Running JUnit Tests on Real Devices

The reliability of JUnit tests depends largely on their execution environment and effectiveness as reliability tools. Emulators and simulators’ preliminary testing capabilities fall short when achieving complete replication of actual usage situations.

BrowserStack Automate enables reliable JUnit testing by providing access to real device cloud with 3,500+ real devices and browsers, to test in real user environment, ensuring accurate performance validation

  • Ensures Real-World Accuracy: Real devices account for hardware variations, network conditions, and system limitations, delivering precise results.
  • Bridges Emulator Limitations: Emulators lack real-world accuracy; only actual devices can test hardware interactions and network fluctuations.
  • Improves Cross-Platform Compatibility: Verifies UI consistency and application performance across multiple devices, OS, and browsers.
  • Enhances Performance Testing: Measures CPU usage, memory consumption, and battery impact for optimized application performance.
  • Accelerates Testing with Parallel Execution: BrowserStack Automate speeds up testing with large-scale parallel execution.
  • Seamless CI/CD Integration: Detects issues early in development, ensuring smooth deployment and flawless user experiences.

Common Errors with MockitoAnnotations.openMocks (With Solutions)

Errors can occur when using MockitoAnnotations.openMocks in JUnit 5 because improper mock management can compromise the execution of tests.

There exist several problems with their corresponding solutions that guarantee trustworthy testing operations.

1. Null Pointer Exception on Mock Objects: If mocks are not initialized before execution, accessing them results in a NullPointerException.

Solution: Call MockitoAnnotations.openMocks(this); inside a @BeforeEach method to ensure that mocks are initialized before each test.

Example:

java
CopyEdit
import org.junit.jupiter.api.BeforeEach;

import org.mockito.MockitoAnnotations;



public class MyTest {

    @BeforeEach

    void setUp() {

        MockitoAnnotations.openMocks(this);

    }

}
Copied

2. Mocks Not Injected Properly: @Mock dependencies are not injected correctly into the class under test, leading to unexpected failures.

Solution: Use @InjectMocks and @Mock to ensure that dependencies are properly injected.

Example:

java
CopyEdit
import org.mockito.InjectMocks;

import org.mockito.Mock;



public class MyTest {

    @Mock

    private Dependency dependency;



    @InjectMocks

    private ClassUnderTest classUnderTest;

}
Copied

3. AutoCloseable Not Closed: If the AutoCloseable resource from openMocks is not closed after the test, it can cause memory leaks.

Solution: Always close the AutoCloseable resource in an @AfterEach method to free up resources properly.

Example:

java
CopyEdit
import org.junit.jupiter.api.AfterEach;

import org.junit.jupiter.api.BeforeEach;

import org.mockito.MockitoAnnotations;



public class MyTest {

    private AutoCloseable closeable;



    @BeforeEach

    void setUp() {

        closeable = MockitoAnnotations.openMocks(this);

    }



    @AfterEach

    void tearDown() throws Exception {

        closeable.close();

    }

}
Copied

Best Practices for Using MockitoAnnotations.openMocks in JUnit 5

Following certain best practices when using MockitoAnnotations.openMocks is important to ensure efficient and error-free unit testing. Proper mock initialization, dependency injection, and resource management improve test maintainability and reliability.

1. Always initialize mocks in @BeforeEach: Mocks should be initialized before each test execution to prevent NullPointerException.

Example:

java
CopyEdit
@BeforeEach

void setUp() {

    MockitoAnnotations.openMocks(this);

}
Copied

2. Prefer openMocks over initMocks: openMocks improves resource management by returning an AutoCloseable instance for proper cleanup, unlike the deprecated initMocks, which lacks this support.

3. Use @InjectMocks for dependency injection: Reduces manual dependency setup by allowing Mockito to inject @Mock dependencies automatically.

Example:

java
CopyEdit
@Mock

private Service service;



@InjectMocks

private Controller controller;
Copied

4. Ensure AutoCloseable is closed properly: Resources should be released after each test to prevent memory leaks.

Example:

java
CopyEdit
@AfterEach

void tearDown() throws Exception {

    closeable.close();

}
Copied

5. Prefer constructor injection over field injection: Constructor injection enhances testability by enforcing explicit dependencies, whereas field injection makes dependencies harder to track and maintain.

6. Run tests on real devices for accurate performance validation: Running tests on real devices ensures accurate functionality validation across different hardware and network conditions, helping teams identify performance issues and improve user experience.

Talk to an Expert

Useful Resources for JUnit

Conclusion

The robust Java framework for JUnit testing consistently strengthens its capabilities to improve test execution. Teams integrating Mockito with JUnit 5 and employing real-device testing can obtain high reliability and scalability in their Java application test automation.

The unit testing process becomes more effective through Mockito by offering powerful tools for creating mocks and dependency injection features. The test process must move past unit testing as real-device testing provides essential conclusive results.

BrowserStack Automate provides a platform for developers to execute tests effortlessly on genuine devices, thus ensuring complete browser and platform compatibility. Parallel testing helps developers execute their tests simultaneously on various configurations, which results in higher efficiency and shorter testing durations.

Try BrowserStack Now

Tags
Automation Testing Real Device Cloud