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
Creating Mocks with
@Mock
:- The
@Mock
annotation creates mock instances of theInventoryService
andPaymentService
interfaces. These mock instances can be used to simulate the behavior of theInventoryService
andPaymentService
in a controlled way.
- The
Injecting Mocks with
@InjectMocks
:- The
@InjectMocks
annotation injects the mockInventoryService
andPaymentService
into theOrderService
instance to provide a controlled test environment. This allows theOrderService
methods to be tested in isolation from the actualInventoryService
andPaymentService
implementations.
- The
Verifying Order of Interactions with
inOrder()
:- The
InOrder inOrder = inOrder(inventoryService, paymentService);
statement creates anInOrder
object to verify the order of interactions with the mock objects. - The
inOrder.verify(inventoryService).checkStock("product123", 2);
method checks if thecheckStock
method was called first on theInventoryService
with the specified arguments. - The
inOrder.verify(inventoryService).reserveProduct("product123", 2);
method checks if thereserveProduct
method was called next on theInventoryService
with the specified arguments. - The
inOrder.verify(paymentService).processPayment(100.0);
method checks if theprocessPayment
method was called last on thePaymentService
with the specified argument.
- The
Verifying No Interactions with
never()
:- The
verify(inventoryService, never()).reserveProduct(anyString(), anyInt());
method checks if thereserveProduct
method was never called on theInventoryService
when the product is out of stock. - The
verify(paymentService, never()).processPayment(anyDouble());
method checks if theprocessPayment
method was never called on thePaymentService
when the product is out of stock.
- The
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
- Verifying Order of Interactions with Single Mock:
- The
InOrder inOrder = inOrder(inventoryService);
statement creates anInOrder
object to verify the order of interactions with the single mock objectinventoryService
. - The
inOrder.verify(inventoryService).checkStock("product123", 2);
method checks if thecheckStock
method was called first on theInventoryService
with the specified arguments. - The
inOrder.verify(inventoryService).reserveProduct("product123", 2);
method checks if thereserveProduct
method was called next on theInventoryService
with the specified arguments.
- The
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
Post a Comment
Leave Comment