The thenDoThrow
method in the BDDMockito
class is part of the Behavior-Driven Development (BDD) style of writing tests using Mockito. It is used to specify that a method on a mock object should throw an exception when called. This method is particularly useful for making tests more readable and aligning with the BDD style, which focuses on describing the behavior of the application in a clear and human-readable format.
Table of Contents
- Introduction
thenDoThrow
Method Syntax- Examples
- Basic Usage
- Using
thenDoThrow
with Different Exceptions
- Real-World Use Case
- Conclusion
Introduction
Behavior-Driven Development (BDD) is a software development approach that emphasizes collaboration between developers, QA, and non-technical or business participants in a software project. Mockito’s BDDMockito
class provides methods that support the BDD style of writing tests. The thenDoThrow
method is used to specify that a method on a mock object should throw an exception when called, making tests more readable and aligning with the BDD approach.
thenDoThrow Method Syntax
Specifying an Exception to be Thrown
import org.mockito.BDDMockito;
static BDDMockito.BDDStubber willDoThrow(Throwable... toBeThrown)
Specifies that the method should throw the given exception when called.
Parameters:
toBeThrown
: The exception(s) to be thrown.
Returns:
- A
BDDStubber
object that allows further stubbing.
Examples
Basic Usage
Use thenDoThrow
to specify that a void method call on a mock object should throw an exception.
import static org.mockito.BDDMockito.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class BasicThenDoThrowTest {
@Test
void testThenDoThrow() {
UserService mockUserService = mock(UserService.class);
// Set up the method to throw an exception
willDoThrow(new RuntimeException("User not found")).given(mockUserService).deleteUser("user123");
// Call the method and verify the exception
Exception exception = assertThrows(RuntimeException.class, () -> {
mockUserService.deleteUser("user123");
});
assertEquals("User not found", exception.getMessage());
}
}
class UserService {
public void deleteUser(String userId) {
// Actual deletion logic
}
}
Using thenDoThrow with Different Exceptions
Use thenDoThrow
to specify that different void method calls on a mock object should throw different exceptions.
import static org.mockito.BDDMockito.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ThenDoThrowDifferentExceptionsTest {
@Test
void testThenDoThrowDifferentExceptions() {
UserService mockUserService = mock(UserService.class);
// Set up the methods to throw different exceptions
willDoThrow(new RuntimeException("User not found")).given(mockUserService).deleteUser("user123");
willDoThrow(new IllegalArgumentException("Invalid user ID")).given(mockUserService).deleteUser("user456");
// Call the methods and verify the exceptions
Exception exception1 = assertThrows(RuntimeException.class, () -> {
mockUserService.deleteUser("user123");
});
assertEquals("User not found", exception1.getMessage());
Exception exception2 = assertThrows(IllegalArgumentException.class, () -> {
mockUserService.deleteUser("user456");
});
assertEquals("Invalid user ID", exception2.getMessage());
}
}
class UserService {
public void deleteUser(String userId) {
// Actual deletion logic
}
}
Real-World Use Case
Simplifying Tests for Services with Exception Handling
In a real-world scenario, you might need to test services with methods that handle exceptions. Using thenDoThrow
can simplify these tests by allowing you to specify the exceptions that should be thrown, making your tests more readable and intuitive.
import static org.mockito.BDDMockito.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
interface EmailService {
void sendEmail(String recipient, String subject, String body) throws EmailException;
}
class UserService {
private final EmailService emailService;
public UserService(EmailService emailService) {
this.emailService = emailService;
}
public void notifyUser(String userId, String message) throws EmailException {
if (userId == null) {
throw new IllegalArgumentException("User ID cannot be null");
}
emailService.sendEmail(userId, "Notification", message);
}
}
class EmailException extends Exception {
public EmailException(String message) {
super(message);
}
}
public class UserServiceTest {
@Test
void testNotifyUserWithException() throws EmailException {
EmailService mockEmailService = mock(EmailService.class);
UserService userService = new UserService(mockEmailService);
// Set up the method to throw an exception
willDoThrow(new EmailException("Email service is down")).given(mockEmailService).sendEmail("user123", "Notification", "Your account has been updated.");
// Call the method and verify the exception
EmailException exception = assertThrows(EmailException.class, () -> {
userService.notifyUser("user123", "Your account has been updated.");
});
assertEquals("Email service is down", exception.getMessage());
}
}
In this example, the UserServiceTest
class uses Mockito’s BDDMockito.thenDoThrow
method to set up the sendEmail
method to throw an exception when called. This simplifies the test by allowing you to specify the exception and verify the behavior in a readable and intuitive way.
Conclusion
The BDDMockito.thenDoThrow
method in Mockito is used for specifying that void methods on mock objects should throw exceptions when called in a BDD style. By using thenDoThrow
, you can make your tests more readable and align them with the BDD approach, focusing on the behavior of the application rather than the implementation details. This helps ensure that your tests are clear, comprehensive, and easy to understand.