🎓 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 doAnswer() method in Mockito is used to specify custom behavior for a method call on a mock object. This is particularly useful when you need to perform more complex operations or handle specific cases that cannot be easily managed with doReturn(), doThrow(), or when(). It allows you to define what should happen when a method on the mock object is called.
When to Use doAnswer()
Use doAnswer() when you need to:
- Perform complex logic: When the behavior of a method cannot be easily defined by simple return values or exceptions.
- Capture method arguments: When you need to inspect or modify the arguments passed to the mock method.
- Invoke a callback or listener: When your method needs to trigger some action in response to being called.
- Combine multiple behaviors: When you need to perform several actions in response to a single method call.
How doAnswer() Works
The doAnswer() method allows you to define a custom Answer implementation that specifies what should happen when the method is called. This Answer can access the arguments passed to the method, perform any necessary logic, and return a value or throw an exception.
Example Scenario
We will create a UserService class that has a dependency on a UserRepository. Our goal is to test the UserService methods using the doAnswer() method in Mockito to handle custom behavior.
UserService and UserRepository Classes
First, create the User class, the UserRepository interface, and the UserService class.
public class User {
private String name;
private String email;
// Constructor, getters, and setters
public User(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
public interface UserRepository {
void saveUser(User user);
User findUserByEmail(String email);
}
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void registerUser(String name, String email) {
User user = new User(name, email);
userRepository.saveUser(user);
}
public User getUserByEmail(String email) {
return userRepository.findUserByEmail(email);
}
}
JUnit 5 Test Class with Mockito
Create a test class for UserService 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.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
public void testRegisterUser() {
// Given
String name = "Ramesh Fadatare";
String email = "ramesh.fadatare@example.com";
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
User user = invocation.getArgument(0);
assertEquals("Ramesh Fadatare", user.getName());
assertEquals("ramesh.fadatare@example.com", user.getEmail());
return null;
}
}).when(userRepository).saveUser(any(User.class));
// When
userService.registerUser(name, email);
// Then
verify(userRepository).saveUser(any(User.class));
}
@Test
public void testGetUserByEmail() {
// Given
String email = "anita.patil@example.com";
User user = new User("Anita Patil", email);
doAnswer(new Answer<User>() {
@Override
public User answer(InvocationOnMock invocation) throws Throwable {
String email = invocation.getArgument(0);
if ("anita.patil@example.com".equals(email)) {
return user;
} else {
return null;
}
}
}).when(userRepository).findUserByEmail(anyString());
// When
User result = userService.getUserByEmail(email);
// Then
assertNotNull(result);
assertEquals("Anita Patil", result.getName());
assertEquals(email, result.getEmail());
}
}
Explanation
Creating Mocks with
@Mock:- The
@Mockannotation creates a mock instance of theUserRepositoryinterface. This mock instance can be used to simulate the behavior of theUserRepositoryin a controlled way.
- The
Injecting Mocks with
@InjectMocks:- The
@InjectMocksannotation injects the mockUserRepositoryinto theUserServiceinstance to provide a controlled test environment. This allows theUserServicemethods to be tested in isolation from the actualUserRepositoryimplementation.
- The
Defining Custom Behavior with
doAnswer():- The
doAnswer(new Answer<Void>() { ... }).when(userRepository).saveUser(any(User.class));method configures the mockUserRepositoryto execute custom behavior when thesaveUsermethod is called with anyUserobject. - Inside the
answermethod, we retrieve the arguments passed to thesaveUsermethod and perform assertions to verify the user's name and email. This allows us to check that theregisterUsermethod of theUserServiceclass correctly interacts with theUserRepository. - Similarly, the
doAnswer(new Answer<User>() { ... }).when(userRepository).findUserByEmail(anyString());method configures the mockUserRepositoryto return a specificUserobject when thefindUserByEmailmethod is called with the specified email. This allows us to check that thegetUserByEmailmethod of theUserServiceclass correctly interacts with theUserRepository.
- The
Verifying Interactions with
verify():- The
verify(userRepository).saveUser(any(User.class));method checks if thesaveUsermethod was called on theUserRepositorywith anyUserobject. This ensures that theregisterUsermethod of theUserServiceclass interacts with theUserRepositorycorrectly.
- The
Use Cases
Use Case 1: Performing Complex Logic
@Test
public void testComplexLogicInMethodCall() {
// Given
String email = "ravi.kumar@example.com";
User user = new User("Ravi Kumar", email);
doAnswer(new Answer<User>() {
@Override
public User answer(InvocationOnMock invocation) throws Throwable {
String email = invocation.getArgument(0);
// Perform complex logic
if ("ravi.kumar@example.com".equals(email)) {
return user;
} else {
return null;
}
}
}).when(userRepository).findUserByEmail(anyString());
// When
User result = userService.getUserByEmail(email);
// Then
assertNotNull(result);
assertEquals("Ravi Kumar", result.getName());
assertEquals(email, result.getEmail());
}
Use Case 2: Capturing and Modifying Arguments
@Test
public void testCaptureAndModifyArguments() {
// Given
String name = "Anjali Sharma";
String email = "anjali.sharma@example.com";
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
User user = invocation.getArgument(0);
user.setName(user.getName().toUpperCase());
return null;
}
}).when(userRepository).saveUser(any(User.class));
// When
userService.registerUser(name, email);
// Then
verify(userRepository).saveUser(argThat(user -> "ANJALI SHARMA".equals(user.getName()) && email.equals(user.getEmail())));
}
Use Case 3: Invoking a Callback
@Test
public void testInvokeCallback() {
// Given
String name = "Rajesh Verma";
String email = "rajesh.verma@example.com";
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
// Invoke a callback
Runnable callback = invocation.getArgument(1);
callback.run();
return null;
}
}).when(userRepository).saveUser(any(User.class), any(Runnable.class));
// When
userService.registerUser(name, email);
// Then
verify(userRepository).saveUser(any(User.class), any(Runnable.class));
}
Conclusion
The doAnswer() method in Mockito simplifies the configuration of custom behavior for method calls on mock objects for unit testing. By using doAnswer(), you can handle complex scenarios and perform specific actions when methods on mock objects are called.
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