🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.
▶️ Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube
▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube
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
@Mockannotation creates a mock instance of thePaymentRepositoryinterface. - This mock instance can be used to simulate the behavior of the
PaymentRepositoryin a controlled way.
- The
Injecting Mocks with
@InjectMocks:- The
@InjectMocksannotation injects the mockPaymentRepositoryinto thePaymentServiceinstance to provide a controlled test environment. - This allows the
PaymentServicemethods to be tested in isolation from the actualPaymentRepositoryimplementation.
- The
Configuring Mock Behavior with
thenThrow():- The
doThrow(new Exception("Payment failed")).when(paymentRepository).savePayment(payment);method configures the mockPaymentRepositoryto throw anExceptionwith the message "Payment failed" when thesavePaymentmethod is called with the specifiedPaymentobject. - Similarly, the
doThrow(new Exception("Payment not found")).when(paymentRepository).findPaymentByTransactionId(transactionId);method configures the mockPaymentRepositoryto throw anExceptionwith the message "Payment not found" when thefindPaymentByTransactionIdmethod is called with the specified transaction ID.
- The
Testing Configured Behavior:
- The
testProcessPaymentThrowsException()method tests theprocessPaymentmethod of thePaymentServiceclass. ThethenThrow()method ensures that the mockPaymentRepositorythrows the expected exception, allowing the exception handling behavior of theprocessPaymentmethod to be verified. - The
testGetPaymentThrowsException()method tests thegetPaymentmethod of thePaymentServiceclass. ThethenThrow()method ensures that the mockPaymentRepositorythrows the expected exception, allowing the exception handling behavior of thegetPaymentmethod 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 mockPaymentRepositoryto throw anIllegalArgumentExceptionwith the message "Invalid payment amount" when thesavePaymentmethod is called with the specifiedPaymentobject.
- The
Testing Configured Behaviors:
- The
testDifferentExceptions()method tests theprocessPaymentmethod of thePaymentServiceclass with a different exception type to verify that the mockPaymentRepositorythrows 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