Using `thenThrow()` effectively with Mockito involves configuring mock objects to throw exceptions when specific methods are called. This is particularly useful for testing how your code handles exceptions from dependencies. Here's a detailed guide on how to use `thenThrow()`:
Basic Usage
The `thenThrow()` method is typically used in conjunction with `when()` to specify that a method call on a mock object should throw an exception. Here's an example:
java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class MyServiceTest {
@Test
void testThrowException() {
// Create a mock object
MyClass mockClass = mock(MyClass.class);
// Configure the mock to throw an exception when someMethod() is called
when(mockClass.someMethod()).thenThrow(new RuntimeException("An error occurred"));
// Verify that the exception is thrown
assertThrows(RuntimeException.class, () -> {
mockClass.someMethod();
});
}
}
Handling Different Exceptions
You can configure different behaviors for a mock method by using `thenThrow()` multiple times with different exceptions. However, when stubbing more than once, the first exception will be thrown upon invoking the second stub, so ensure you test each scenario separately:
java
@Test
void testDifferentExceptions() {
MyClass mockClass = mock(MyClass.class);
// First test case: Throw one type of exception
when(mockClass.someMethod()).thenThrow(new RuntimeException("Runtime error"));
assertThrows(RuntimeException.class, () -> {
mockClass.someMethod();
});
// Reset the mock for the next test case
// mockClass = mock(MyClass.class); // If needed
// Second test case: Throw another type of exception
when(mockClass.someMethod()).thenThrow(new IllegalArgumentException("Invalid argument"));
assertThrows(IllegalArgumentException.class, () -> {
mockClass.someMethod();
});
}
Void Methods
For methods that return `void`, you cannot use `when().thenThrow()` directly because there is no return value to mock. Instead, use `doThrow()`:
java
@Test
void testThrowExceptionInVoidMethod() {
MyClass mockClass = mock(MyClass.class);
// Configure the mock to throw an exception when voidMethod() is called
doThrow(new IllegalArgumentException("Invalid argument")).when(mockClass).voidMethod();
// Verify that the exception is thrown
assertThrows(IllegalArgumentException.class, () -> {
mockClass.voidMethod();
});
}
Best Practices
- Use Specific Exceptions: Always use specific exception types (e.g., `IllegalArgumentException`, `IOException`) instead of general exceptions like `Exception` to ensure your tests are precise and meaningful.
- Test Exception Handling: Use `assertThrows()` to verify that the expected exception is thrown, ensuring your code handles exceptions correctly.
- Reset Mocks: If you're testing multiple scenarios with the same mock, consider resetting the mock between tests to avoid unexpected behavior.
By following these guidelines, you can effectively use `thenThrow()` with Mockito to test how your code handles exceptions from dependencies, ensuring robust error handling in your application.
Citations:[1] https://www.javaguides.net/2023/10/mockito-thenthrow.html
[2] https://github.com/mockito/mockito/issues/282
[3] https://reflectoring.io/clean-unit-tests-with-mockito/
[4] https://dev.to/realnamehidden1_61/thenthrow-method-in-mockito-example-460l
[5] https://www.janbasktraining.com/community/java/throw-checked-exceptions-from-mocks-with-mockito
[6] https://stackoverflow.com/questions/51374553/mockito-not-throwing-exception-using-thenthrow
[7] https://www.vogella.com/tutorials/Mockito/article.html
[8] https://www.reddit.com/r/SpringBoot/comments/wrzpkp/i_need_to_write_a_test_case_where_that/
[9] https://www.toptal.com/java/a-guide-to-everyday-mockito
[10] https://www.browserstack.com/guide/mockito-throw-exception