Basics of Mocking Dependencies in Java Unit Tests with Mockito

Alexander Obregon
6 min readMay 22, 2024

--

Image Source

Introduction

Unit testing is an important part of software development, making sure that individual components of an application work as intended. In Java, the Mockito framework is a powerful tool for creating mock objects and defining their behavior, allowing developers to test components in isolation. This article will go into how to use Mockito to mock dependencies in your Java unit tests, along with some examples.

Basics of Unit Testing, Mocking, and Setting Up Mockito

The purpose of unit testing is to validate that each unit of the software performs as expected. Mocking, on the other hand, is a technique where objects are replaced with simulated versions that mimic the behavior of real objects, allowing for isolated testing of components.

Importance of Unit Testing and Mocking

Unit testing is essential for ensuring that individual components of an application work correctly. It helps in identifying bugs early in the development process, making maintenance easier, and improving the overall quality of the software. Mocking allows developers to test a unit in isolation by simulating dependencies, thus focusing solely on the functionality of the unit under test.

Setting Up Mockito in Your Project

Mockito is a popular framework used for mocking objects in Java unit tests. To start using Mockito, you need to include it as a dependency in your project. If you’re using Maven, you can add the following dependency to your pom.xml file:

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

For Gradle, add this to your build.gradle file:

testImplementation 'org.mockito:mockito-core:4.12.0'

Once you have added the dependency, you can start creating and using mock objects in your tests.

Basic Concepts of Mockito

Mockito is a powerful framework for creating mock objects in Java unit tests. It allows developers to test components in isolation by simulating dependencies. To effectively use Mockito, it’s essential to understand its basic concepts: mocking, stubbing, and verifying.

Mocking

Mocking is the process of creating a simulated version of an object. This is useful when the real object is impractical to incorporate into a test, such as when it involves complex setup, slow operations, or external dependencies like databases or web services.

To create a mock object in Mockito, you use the Mockito.mock() method. For example:

OrderRepository mockRepository = Mockito.mock(OrderRepository.class);

This creates a mock object of the OrderRepository class. The mock object can now be used in place of a real OrderRepository object in your tests.

Stubbing

Stubbing is the process of defining the behavior of a mock object. When a method on a mock object is called, it can return a predefined result, throw an exception, or perform some other behavior.

In Mockito, stubbing is done using the when method followed by the desired behavior using thenReturn, thenThrow, or other methods. Here’s an example:

Order mockOrder = new Order(1, "Sample Order");
when(mockRepository.findById(1)).thenReturn(mockOrder);

In this example, when the findById method of mockRepository is called with the argument 1, it returns the mockOrder object. You can also define behavior for methods with more complex interactions:

when(mockRepository.save(any(Order.class))).thenAnswer(invocation -> {
Order order = invocation.getArgument(0);
order.setId(1);
return order;
});

This example shows how to use an Answer to define more complex stubbing behavior.

Verifying

Verification is the process of checking that specific methods on a mock object were called with the expected arguments. This makes sure that your code interacts with its dependencies as intended.

Mockito provides the verify method for this purpose. Here’s an example:

verify(mockRepository, times(1)).findById(1);

This verifies that the findById method was called exactly once with the argument 1. You can also check for more complex interactions:

verify(mockRepository, never()).delete(any(Order.class));

This verifies that the delete method was never called on mockRepository.

Argument Matchers

Mockito provides argument matchers to specify flexible matching rules for method arguments. These are useful when you want to verify or stub methods without being tied to specific argument values.

Common argument matchers include any(), anyInt(), anyString(), and so on. Here’s an example:

when(mockRepository.findById(anyInt())).thenReturn(mockOrder);

In this example, the findById method returns mockOrder regardless of the integer argument provided. Argument matchers can also be used in verification:

verify(mockRepository).save(any(Order.class));

Capturing Arguments

Sometimes, you need to capture arguments passed to a method on a mock object for further assertions. Mockito provides the ArgumentCaptor class for this purpose. Here’s an example:

ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
verify(mockRepository).findById(captor.capture());
assertEquals(1, captor.getValue());

This example captures the argument passed to the findById method and asserts that it is 1.

Mocking Static Methods

Since Mockito 3.4.0, it is possible to mock static methods. This feature can be particularly useful for legacy code or utility classes. Here’s an example:

try (MockedStatic<StaticClass> mockedStatic = mockStatic(StaticClass.class)) {
mockedStatic.when(StaticClass::staticMethod).thenReturn("mocked value");

// Perform your test with the static method mocked
String result = StaticClass.staticMethod();
assertEquals("mocked value", result);
}

This example demonstrates how to use MockedStatic to mock a static method.

Understanding these basic concepts will help you use Mockito effectively in your Java unit tests. In the next section, we will explore these concepts with practical examples.

Example: Mocking Dependencies with Mockito

To understand how to use Mockito effectively, let’s consider a practical example. We will create a simple service class, OrderService, which depends on a repository class, OrderRepository. Our goal is to test OrderService in isolation by mocking its dependency on OrderRepository.

The Service and Repository Classes

First, let’s define the OrderService and OrderRepository classes:

public class OrderService {
private OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

public Order getOrderById(int id) {
return orderRepository.findById(id);
}
}

public class OrderRepository {
public Order findById(int id) {
// Imagine this method interacts with a database to retrieve the order
return new Order(id, "Order " + id);
}
}

public class Order {
private int id;
private String name;

public Order(int id, String name) {
this.id = id;
this.name = name;
}

public int getId() {
return id;
}

public String getName() {
return name;
}

public void setId(int id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}
}

In this example, OrderService depends on OrderRepository to retrieve orders. The Order class represents an order with an id and name.

Writing the Unit Test

To test OrderService in isolation, we need to mock OrderRepository. Here's how we can write the unit test using Mockito:

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

public class OrderServiceTest {

@Test
public void testGetOrderById() {
// Create a mock for OrderRepository
OrderRepository mockRepository = Mockito.mock(OrderRepository.class);

// Define the behavior of the mock
Order mockOrder = new Order(1, "Sample Order");
when(mockRepository.findById(1)).thenReturn(mockOrder);

// Inject the mock into the service
OrderService orderService = new OrderService(mockRepository);

// Perform the test
Order order = orderService.getOrderById(1);

// Verify the result
assertEquals("Sample Order", order.getName());
verify(mockRepository, times(1)).findById(1);
}
}

Breakdown of the Test

  1. Creating a Mock Object: We create a mock object for OrderRepository using Mockito.mock(OrderRepository.class).
  2. Defining Behavior: We define the behavior of the mock object using when and thenReturn. In this case, when the findById method is called with the argument 1, it returns a predefined Order object.
  3. Injecting the Mock: We inject the mock OrderRepository into OrderService. This allows us to test OrderService in isolation from OrderRepository.
  4. Performing the Test: We call the getOrderById method on OrderService and store the result.
  5. Verifying the Result: We use assertEquals to verify that the Order object returned by getOrderById has the expected name. We also use verify to make sure that the findById method on the mock OrderRepository was called exactly once with the argument 1.

Conclusion

Understanding how to mock dependencies with Mockito is essential for effective unit testing in Java. By simulating dependencies, you can test your components in isolation, making sure they work correctly and reliably. With the knowledge of basic concepts like mocking, stubbing, and verifying, along with practical examples, you are well-equipped to write strong unit tests. Mockito’s powerful features help maintain the quality and integrity of your codebase, making it a valuable tool in any Java developer’s toolkit.

  1. Mockito Official Documentation
  2. JUnit 5 User Guide
  3. Test-Driven Development (TDD)
  4. Mockito GitHub Repository

Thank you for reading! If you find this article helpful, please consider highlighting, clapping, responding or connecting with me on Twitter/X as it’s very appreciated and helps keeps content like this free!

--

--

Alexander Obregon

Software Engineer, fervent coder & writer. Devoted to learning & assisting others. Connect on LinkedIn: https://www.linkedin.com/in/alexander-obregon-97849b229/