Introduction
The spy()
method in Mockito is used to create spy objects. A spy is a partial mock, which means that it can call real methods while still allowing certain methods to be stubbed. This is particularly useful when you want to test real method behavior while controlling the behavior of specific methods. This tutorial will demonstrate how to use the spy()
method in Mockito to create and configure spy objects.
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 BankAccount
class with methods for depositing and withdrawing money. Our goal is to test the BankAccount
methods using the spy()
method in Mockito to create a spy object that calls real methods while allowing specific methods to be stubbed.
BankAccount Class
First, create the BankAccount
class.
public class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}
JUnit 5 Test Class with Mockito
Create a test class for BankAccount
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.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(MockitoExtension.class)
public class BankAccountTest {
@Spy
private BankAccount bankAccountSpy = new BankAccount(100.0);
@Test
public void testDeposit() {
// Given
// No need to stub the deposit method, we want to use the real method
// When
bankAccountSpy.deposit(50.0);
// Then
assertEquals(150.0, bankAccountSpy.getBalance());
}
@Test
public void testWithdraw() {
// Given
doNothing().when(bankAccountSpy).withdraw(50.0);
// When
bankAccountSpy.withdraw(50.0);
// Then
assertEquals(100.0, bankAccountSpy.getBalance());
}
@Test
public void testWithdrawRealMethod() {
// Given
// No stubbing for withdraw, so the real method will be called
// When
bankAccountSpy.withdraw(50.0);
// Then
assertEquals(50.0, bankAccountSpy.getBalance());
}
}
Explanation
Creating Spies with
spy()
:- The
@Spy
annotation creates a spy instance of theBankAccount
class with an initial balance of100.0
. Alternatively, you can useBankAccount bankAccountSpy = spy(new BankAccount(100.0));
to create a spy instance. - A spy calls real methods by default, but you can still stub specific methods to control their behavior.
- The
Testing Real Method Behavior:
- The
testDeposit()
method tests the realdeposit
method of theBankAccount
class. Since no stubbing is needed, the real method is called and its behavior is verified.
- The
Stubbing Specific Methods:
- The
testWithdraw()
method usesdoNothing().when(bankAccountSpy).withdraw(50.0);
to stub thewithdraw
method. This controls the behavior of thewithdraw
method, making it do nothing instead of calling the real method.
- The
Verifying Real Method Calls:
- The
testWithdrawRealMethod()
method tests the realwithdraw
method without any stubbing. The real method is called and its behavior is verified.
- The
Additional Scenarios
Scenario: Combining Real and Stubbed Methods
In this scenario, we will demonstrate how to combine real and stubbed methods in a single test.
@Test
public void testDepositAndWithdraw() {
// Given
doNothing().when(bankAccountSpy).withdraw(50.0);
// When
bankAccountSpy.deposit(50.0);
bankAccountSpy.withdraw(50.0);
// Then
assertEquals(150.0, bankAccountSpy.getBalance()); // Real deposit method
// Balance remains 150.0 because withdraw was stubbed
}
Explanation
Stubbing a Specific Method:
doNothing().when(bankAccountSpy).withdraw(50.0);
stubs thewithdraw
method to do nothing when called with50.0
.
Calling Real Methods:
- The
deposit
method is called without stubbing, so the real method is executed, and its behavior is verified.
- The
Combining Real and Stubbed Methods:
- Both real and stubbed methods are combined in a single test, demonstrating the flexibility of using spies.
Conclusion
The spy()
method in Mockito allows you to create partial mocks, enabling you to call real methods while still being able to stub specific methods. By using spy()
, you can test the behavior of your code more comprehensively, combining real and controlled method behavior. This step-by-step guide demonstrated how to effectively use the spy()
method in your unit tests, covering different scenarios to ensure comprehensive testing of the BankAccount
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