Best Practices for Java Testing with Mockito

Samuel Catalano
3 min readJan 31, 2023

Mockito is a popular testing framework for Java that enables developers to create mock objects for unit testing. Unit testing is a technique that involves testing individual components of a software application in isolation. The purpose of unit testing is to verify the correctness of the individual components, as well as to identify any issues early in the development process.

It allows developers to simulate the behaviour of external dependencies, making it possible to test individual components in isolation. This is especially useful for testing complex systems, where the behaviour of external dependencies can be unpredictable or hard to control.

Best Practices for Using Mockito

Use Mock Objects for Isolated Testing

The first step in using Mockito is to create mock objects for the dependencies in your code. By testing each unit in isolation, you can verify its behaviour without relying on the behaviour of external dependencies. This makes it easier to identify and fix any issues early in the development process.

Verify Behavior, Not Implementation

When testing a method, it’s important to focus on the behaviour of the method, rather than its implementation details. This helps to ensure that the tests are robust and maintainable, as well as makes it easier to make changes to the implementation without affecting the tests.

Use ArgumentCaptor for Complex Argument Matching

ArgumentCaptor is a powerful feature of Mockito that enables you to capture and verify method arguments in a more flexible and readable manner. This can be especially useful when testing methods that take complex arguments, such as collections or custom objects.

Use thenCallRealMethod Wisely

thenCallRealMethod() is a feature of Mockito that allows you to call the real implementation of a method, rather than the mocked version. While this can be useful in certain situations, it’s important to use it wisely, as it makes the test less isolated and harder to understand.

Use Annotations like @Mock and @InjectMocks

Mockito provides several annotations, such as @Mock and @InjectMocks, that make it easier to create and inject mock objects into your tests. By using these annotations, you can reduce the amount of boilerplate code required to set up your tests, as well as make the tests more readable.

Avoid Using reset()

Reset is a feature of Mockito that enables you to clear the state of a mock object. While this can be useful in certain situations, it’s important to use it with caution, as it can make the tests fragile and hard to understand. A better approach is to use annotations like @Before to create a fresh mock object before each test.

Code Example

Here’s a code example that demonstrates some of the best practices for using Mockito.

import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class ExampleTest {

@Mock
private Dependency dependency;

@InjectMocks
private Service service;

@Captor
private ArgumentCaptor<String> argumentCaptor;

@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}

@Test
public void testService() {
// arrange
when(dependency.doSomething("input")).thenReturn("output");

// act
String result = service.useDependency("input");

// assert
verify(dependency).doSomething(argumentCaptor.capture());
assertEquals("input", argumentCaptor.getValue());
assertEquals("output", result);
}
}

In this code example, we’re using the @Mock annotation to create a mock object for the Dependency class. We're also using the @InjectMocks annotation to inject the mock object into an instance of the Service class. This makes it possible to test the Service class in isolation, without relying on the behaviour of the Dependency class.

We’re also using the @Captor annotation to create an ArgumentCaptor object, which makes it possible to capture and verify the arguments passed to the doSomething method of the Dependency class. This is a more flexible and readable way to test the arguments passed to the method, compared to using eq or other argument matchers.

In the testService method, we're using the when method to stub the behaviour of the doSomething method. We're also using the verify method to verify that the doSomething method was called with the expected argument. Finally, we're using the assertEquals method to verify the result of the useDependency method.

Conclusion

Mockito is a powerful testing framework for Java that enables developers to create mock objects for unit testing. By following these best practices, you can ensure that your tests are robust, maintainable, and easy to understand. Whether you’re testing complex systems or simple components, Mockito can help you verify the behaviour of your code and identify any issues early in the development process.

--

--

Samuel Catalano

Samuel is a Software Engineer from Brazil with main interests in Java, Spring Boot, Quarkus, Microservices, Docker, Databases, Kubernetes, and Clean Code