Introduction
The doThrow()
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 doThrow()
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 BankService
class that has a dependency on a BankRepository
. Our goal is to test how the BankService
handles exceptions thrown by the BankRepository
using the doThrow()
method in Mockito.
BankService and BankRepository Classes
First, create the Account
class, the BankRepository
interface, and the BankService
class.
public class Account {
private String accountNumber;
private double balance;
// Constructor, getters, and setters
public Account(String accountNumber, double balance) {
this.accountNumber = accountNumber;
this.balance = balance;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
public interface BankRepository {
Account findAccountByNumber(String accountNumber) throws Exception;
void withdraw(String accountNumber, double amount) throws Exception;
}
public class BankService {
private final BankRepository bankRepository;
public BankService(BankRepository bankRepository) {
this.bankRepository = bankRepository;
}
public Account getAccountDetails(String accountNumber) throws Exception {
return bankRepository.findAccountByNumber(accountNumber);
}
public void withdrawAmount(String accountNumber, double amount) throws Exception {
bankRepository.withdraw(accountNumber, amount);
}
}
JUnit 5 Test Class with Mockito
Create a test class for BankService
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 BankServiceTest {
@Mock
private BankRepository bankRepository;
@InjectMocks
private BankService bankService;
@Test
public void testGetAccountDetails() throws Exception {
// Given
String accountNumber = "12345";
Account account = new Account(accountNumber, 1000.0);
when(bankRepository.findAccountByNumber(accountNumber)).thenReturn(account);
// When
Account result = bankService.getAccountDetails(accountNumber);
// Then
assertNotNull(result);
assertEquals(accountNumber, result.getAccountNumber());
assertEquals(1000.0, result.getBalance());
}
@Test
public void testWithdrawAmountThrowsException() {
// Given
String accountNumber = "12345";
doThrow(new Exception("Insufficient funds")).when(bankRepository).withdraw(accountNumber, 500.0);
// When & Then
Exception exception = assertThrows(Exception.class, () -> {
bankService.withdrawAmount(accountNumber, 500.0);
});
assertEquals("Insufficient funds", exception.getMessage());
}
}
Explanation
Creating Mocks with
@Mock
:- The
@Mock
annotation creates a mock instance of theBankRepository
interface. This mock instance can be used to simulate the behavior of theBankRepository
in a controlled way.
- The
Injecting Mocks with
@InjectMocks
:- The
@InjectMocks
annotation injects the mockBankRepository
into theBankService
instance to provide a controlled test environment. This allows theBankService
methods to be tested in isolation from the actualBankRepository
implementation.
- The
Configuring Mock Behavior with
doThrow()
:- The
doThrow(new Exception("Insufficient funds")).when(bankRepository).withdraw(accountNumber, 500.0);
method configures the mockBankRepository
to throw anException
with the message "Insufficient funds" when thewithdraw
method is called with the specified account number and amount. This allows thewithdrawAmount
method of theBankService
class to be tested with controlled exception handling behavior from theBankRepository
.
- The
Testing Configured Behavior:
- The
testWithdrawAmountThrowsException()
method tests thewithdrawAmount
method of theBankService
class. ThedoThrow()
method ensures that the mockBankRepository
throws the expected exception, allowing the exception-handling behavior of thewithdrawAmount
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 doThrow()
method.
@Test
public void testWithdrawAmountWithDifferentExceptions() {
// Given
String accountNumber = "12345";
doThrow(new IllegalArgumentException("Invalid amount")).when(bankRepository).withdraw(accountNumber, -100.0);
// When & Then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
bankService.withdrawAmount(accountNumber, -100.0);
});
assertEquals("Invalid amount", exception.getMessage());
}
Explanation
Configuring Different Exceptions:
- The
doThrow(new IllegalArgumentException("Invalid amount")).when(bankRepository).withdraw(accountNumber, -100.0);
method configures the mockBankRepository
to throw anIllegalArgumentException
with the message "Invalid amount" when thewithdraw
method is called with the specified account number and negative amount. This allows thewithdrawAmount
method of theBankService
class to be tested with different exception handling scenarios.
- The
Testing Configured Behaviors:
- The
testWithdrawAmountWithDifferentExceptions()
method tests thewithdrawAmount
method of theBankService
class with a different exception type to verify that the mockBankRepository
throws the expected exception.
- The
Conclusion
The doThrow()
method in Mockito simplifies the configuration of mock objects to throw exceptions for unit testing. By using doThrow()
, 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 doThrow()
method in your unit tests, covering different scenarios to ensure comprehensive testing of the BankService
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