Mockito inOrder()

Introduction

The inOrder() method in Mockito is used to verify that interactions with mock objects occur in a specific sequence. This is particularly useful when the order of method calls is important. This tutorial will demonstrate how to use the inOrder() method in Mockito to verify the sequence of method invocations.

Maven Dependencies

To use Mockito with JUnit 5, add the following dependencies to your pom.xml file:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

Example Scenario

We will create a OrderService class that has dependencies on InventoryService and PaymentService. Our goal is to test the OrderService methods using the inOrder() method in Mockito to verify the sequence of interactions with InventoryService and PaymentService.

OrderService, InventoryService, and PaymentService Classes

First, create the Order, InventoryService, PaymentService, and OrderService classes.

public class Order {
    private String productId;
    private int quantity;
    private double price;

    // Constructor, getters, and setters
    public Order(String productId, int quantity, double price) {
        this.productId = productId;
        this.quantity = quantity;
        this.price = price;
    }

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

public interface InventoryService {
    boolean checkStock(String productId, int quantity);
    void reserveProduct(String productId, int quantity);
}

public interface PaymentService {
    void processPayment(double amount);
}

public class OrderService {
    private final InventoryService inventoryService;
    private final PaymentService paymentService;

    public OrderService(InventoryService inventoryService, PaymentService paymentService) {
        this.inventoryService = inventoryService;
        this.paymentService = paymentService;
    }

    public void placeOrder(Order order) {
        if (inventoryService.checkStock(order.getProductId(), order.getQuantity())) {
            inventoryService.reserveProduct(order.getProductId(), order.getQuantity());
            paymentService.processPayment(order.getPrice() * order.getQuantity());
        }
    }
}

JUnit 5 Test Class with Mockito

Create a test class for OrderService using JUnit 5 and Mockito.

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.InOrder;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(MockitoExtension.class)
public class OrderServiceTest {

    @Mock
    private InventoryService inventoryService;

    @Mock
    private PaymentService paymentService;

    @InjectMocks
    private OrderService orderService;

    @Test
    public void testPlaceOrder() {
        // Given
        Order order = new Order("product123", 2, 50.0);
        when(inventoryService.checkStock("product123", 2)).thenReturn(true);

        // When
        orderService.placeOrder(order);

        // Then
        InOrder inOrder = inOrder(inventoryService, paymentService);
        inOrder.verify(inventoryService).checkStock("product123", 2);
        inOrder.verify(inventoryService).reserveProduct("product123", 2);
        inOrder.verify(paymentService).processPayment(100.0);
    }

    @Test
    public void testPlaceOrderOutOfStock() {
        // Given
        Order order = new Order("product123", 2, 50.0);
        when(inventoryService.checkStock("product123", 2)).thenReturn(false);

        // When
        orderService.placeOrder(order);

        // Then
        verify(inventoryService).checkStock("product123", 2);
        verify(inventoryService, never()).reserveProduct(anyString(), anyInt());
        verify(paymentService, never()).processPayment(anyDouble());
    }
}

Explanation

  1. Creating Mocks with @Mock:

    • The @Mock annotation creates mock instances of the InventoryService and PaymentService interfaces. These mock instances can be used to simulate the behavior of the InventoryService and PaymentService in a controlled way.
  2. Injecting Mocks with @InjectMocks:

    • The @InjectMocks annotation injects the mock InventoryService and PaymentService into the OrderService instance to provide a controlled test environment. This allows the OrderService methods to be tested in isolation from the actual InventoryService and PaymentService implementations.
  3. Verifying Order of Interactions with inOrder():

    • The InOrder inOrder = inOrder(inventoryService, paymentService); statement creates an InOrder object to verify the order of interactions with the mock objects.
    • The inOrder.verify(inventoryService).checkStock("product123", 2); method checks if the checkStock method was called first on the InventoryService with the specified arguments.
    • The inOrder.verify(inventoryService).reserveProduct("product123", 2); method checks if the reserveProduct method was called next on the InventoryService with the specified arguments.
    • The inOrder.verify(paymentService).processPayment(100.0); method checks if the processPayment method was called last on the PaymentService with the specified argument.
  4. Verifying No Interactions with never():

    • The verify(inventoryService, never()).reserveProduct(anyString(), anyInt()); method checks if the reserveProduct method was never called on the InventoryService when the product is out of stock.
    • The verify(paymentService, never()).processPayment(anyDouble()); method checks if the processPayment method was never called on the PaymentService when the product is out of stock.

Additional Scenarios

Scenario: Verifying Order of Interactions with Single Mock

In this scenario, we will demonstrate how to verify the order of interactions with a single mock object using the inOrder() method.

@Test
public void testPlaceOrderWithSingleMock() {
    // Given
    Order order = new Order("product123", 2, 50.0);
    when(inventoryService.checkStock("product123", 2)).thenReturn(true);

    // When
    orderService.placeOrder(order);

    // Then
    InOrder inOrder = inOrder(inventoryService);
    inOrder.verify(inventoryService).checkStock("product123", 2);
    inOrder.verify(inventoryService).reserveProduct("product123", 2);
}

Explanation

  1. Verifying Order of Interactions with Single Mock:
    • The InOrder inOrder = inOrder(inventoryService); statement creates an InOrder object to verify the order of interactions with the single mock object inventoryService.
    • The inOrder.verify(inventoryService).checkStock("product123", 2); method checks if the checkStock method was called first on the InventoryService with the specified arguments.
    • The inOrder.verify(inventoryService).reserveProduct("product123", 2); method checks if the reserveProduct method was called next on the InventoryService with the specified arguments.

Conclusion

The inOrder() method in Mockito simplifies the verification of the order of method calls on mock objects for unit testing. By using inOrder(), you can ensure that the code under test interacts with its dependencies in the correct sequence. This step-by-step guide demonstrated how to effectively use the inOrder() method in your unit tests, covering different scenarios to ensure comprehensive testing of the OrderService class.

Related Mockito Methods

Mockito mock()
Mockito spy()
Mockito when()
Mockito thenThrow()
Mockito verify()
Mockito times()
Mockito never()
Mockito any()
Mockito eq()
Mockito inOrder()
Mockito doReturn()
Mockito doThrow()
Mockito doAnswer()
Mockito timeout()
Mockito ArgumentMatchers

Comments