Introduction
The thenThrow()
method in Mockito is used to specify that a method call on a mock object should throw an exception. This is particularly useful when you want to test how your code handles exceptions from dependencies. This tutorial will demonstrate how to use the thenThrow()
method in Mockito to configure mock objects to throw exceptions.
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 PaymentService
class that has a dependency on a PaymentRepository
. Our goal is to test how the PaymentService
handles exceptions thrown by the PaymentRepository
using the thenThrow()
method in Mockito.
PaymentService and PaymentRepository Classes
First, create the Payment
class, the PaymentRepository
interface, and the PaymentService
class.
public class Payment {
private String transactionId;
private double amount;
// Constructor, getters, and setters
public Payment(String transactionId, double amount) {
this.transactionId = transactionId;
this.amount = amount;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
}
public interface PaymentRepository {
void savePayment(Payment payment) throws Exception;
Payment findPaymentByTransactionId(String transactionId) throws Exception;
}
public class PaymentService {
private final PaymentRepository paymentRepository;
public PaymentService(PaymentRepository paymentRepository) {
this.paymentRepository = paymentRepository;
}
public void processPayment(Payment payment) throws Exception {
paymentRepository.savePayment(payment);
}
public Payment getPayment(String transactionId) throws Exception {
return paymentRepository.findPaymentByTransactionId(transactionId);
}
}
JUnit 5 Test Class with Mockito
Create a test class for PaymentService
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.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(MockitoExtension.class)
public class PaymentServiceTest {
@Mock
private PaymentRepository paymentRepository;
@InjectMocks
private PaymentService paymentService;
@Test
public void testProcessPaymentThrowsException() {
// Given
Payment payment = new Payment("12345", 100.0);
doThrow(new Exception("Payment failed")).when(paymentRepository).savePayment(payment);
// When & Then
Exception exception = assertThrows(Exception.class, () -> {
paymentService.processPayment(payment);
});
assertEquals("Payment failed", exception.getMessage());
}
@Test
public void testGetPaymentThrowsException() {
// Given
String transactionId = "12345";
doThrow(new Exception("Payment not found")).when(paymentRepository).findPaymentByTransactionId(transactionId);
// When & Then
Exception exception = assertThrows(Exception.class, () -> {
paymentService.getPayment(transactionId);
});
assertEquals("Payment not found", exception.getMessage());
}
}
Explanation
Creating Mocks with
@Mock
:- The
@Mock
annotation creates a mock instance of thePaymentRepository
interface. - This mock instance can be used to simulate the behavior of the
PaymentRepository
in a controlled way.
- The
Injecting Mocks with
@InjectMocks
:- The
@InjectMocks
annotation injects the mockPaymentRepository
into thePaymentService
instance to provide a controlled test environment. - This allows the
PaymentService
methods to be tested in isolation from the actualPaymentRepository
implementation.
- The
Configuring Mock Behavior with
thenThrow()
:- The
doThrow(new Exception("Payment failed")).when(paymentRepository).savePayment(payment);
method configures the mockPaymentRepository
to throw anException
with the message "Payment failed" when thesavePayment
method is called with the specifiedPayment
object. - Similarly, the
doThrow(new Exception("Payment not found")).when(paymentRepository).findPaymentByTransactionId(transactionId);
method configures the mockPaymentRepository
to throw anException
with the message "Payment not found" when thefindPaymentByTransactionId
method is called with the specified transaction ID.
- The
Testing Configured Behavior:
- The
testProcessPaymentThrowsException()
method tests theprocessPayment
method of thePaymentService
class. ThethenThrow()
method ensures that the mockPaymentRepository
throws the expected exception, allowing the exception handling behavior of theprocessPayment
method to be verified. - The
testGetPaymentThrowsException()
method tests thegetPayment
method of thePaymentService
class. ThethenThrow()
method ensures that the mockPaymentRepository
throws the expected exception, allowing the exception handling behavior of thegetPayment
method to be verified.
- The
Additional Scenarios
Scenario: Handling Different Exceptions
In this scenario, we will demonstrate how to configure different behaviors for a mock method using the thenThrow()
method.
@Test
public void testDifferentExceptions() {
// Given
Payment payment = new Payment("12345", 100.0);
doThrow(new IllegalArgumentException("Invalid payment amount")).when(paymentRepository).savePayment(payment);
// When & Then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
paymentService.processPayment(payment);
});
assertEquals("Invalid payment amount", exception.getMessage());
}
Explanation
Configuring Different Exceptions:
- The
doThrow(new IllegalArgumentException("Invalid payment amount")).when(paymentRepository).savePayment(payment);
method configures the mockPaymentRepository
to throw anIllegalArgumentException
with the message "Invalid payment amount" when thesavePayment
method is called with the specifiedPayment
object.
- The
Testing Configured Behaviors:
- The
testDifferentExceptions()
method tests theprocessPayment
method of thePaymentService
class with a different exception type to verify that the mockPaymentRepository
throws the expected exception.
- The
Conclusion
The thenThrow()
method in Mockito simplifies the configuration of mock objects to throw exceptions for unit testing. By using thenThrow()
, you can easily define the behavior of mock methods when exceptions need to be tested, allowing you to verify the exception handling logic in your code. This step-by-step guide demonstrated how to effectively use the thenThrow()
method in your unit tests, covering different scenarios to ensure comprehensive testing of the PaymentService
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