🎓 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
Mocking void methods in Mockito can be accomplished using the doNothing(), doThrow(), doAnswer(), doReturn(), and doCallRealMethod() methods. This is particularly useful when you want to control the behavior of a void method, which cannot return a value. This tutorial will demonstrate how to mock void methods in Mockito using different approaches.
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 NotificationService class that has a dependency on an EmailService. Our goal is to test the NotificationService methods by mocking the EmailService void methods.
NotificationService and EmailService Classes
First, create the Email class, the EmailService interface, and the NotificationService class.
public class Email {
private String recipient;
private String message;
// Constructor, getters, and setters
public Email(String recipient, String message) {
this.recipient = recipient;
this.message = message;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
public interface EmailService {
void sendEmail(Email email);
}
public class NotificationService {
private final EmailService emailService;
public NotificationService(EmailService emailService) {
this.emailService = emailService;
}
public void sendNotification(String recipient, String message) {
Email email = new Email(recipient, message);
emailService.sendEmail(email);
}
}
JUnit 5 Test Class with Mockito
Create a test class for NotificationService 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 NotificationServiceTest {
@Mock
private EmailService emailService;
@InjectMocks
private NotificationService notificationService;
@Test
public void testSendNotificationWithDoNothing() {
// Given
String recipient = "test@example.com";
String message = "Hello, World!";
// Mock void method
doNothing().when(emailService).sendEmail(any(Email.class));
// When
notificationService.sendNotification(recipient, message);
// Then
verify(emailService, times(1)).sendEmail(any(Email.class));
}
@Test
public void testSendNotificationWithDoThrow() {
// Given
String recipient = "test@example.com";
String message = "Hello, World!";
// Mock void method to throw an exception
doThrow(new RuntimeException("Email service is down")).when(emailService).sendEmail(any(Email.class));
// When & Then
RuntimeException exception = assertThrows(RuntimeException.class, () -> {
notificationService.sendNotification(recipient, message);
});
assertEquals("Email service is down", exception.getMessage());
}
@Test
public void testSendNotificationWithDoAnswer() {
// Given
String recipient = "test@example.com";
String message = "Hello, World!";
// Mock void method with custom behavior
doAnswer(invocation -> {
Email email = invocation.getArgument(0);
assertEquals("test@example.com", email.getRecipient());
assertEquals("Hello, World!", email.getMessage());
return null;
}).when(emailService).sendEmail(any(Email.class));
// When
notificationService.sendNotification(recipient, message);
// Then
verify(emailService, times(1)).sendEmail(any(Email.class));
}
@Test
public void testSendNotificationWithDoCallRealMethod() {
// Given
String recipient = "test@example.com";
String message = "Hello, World!";
// Mock void method to call real method
doCallRealMethod().when(emailService).sendEmail(any(Email.class));
// Here you would need an implementation of the sendEmail method in EmailService
// For this example, assume it's a real implementation that you want to test
// When
notificationService.sendNotification(recipient, message);
// Then
verify(emailService, times(1)).sendEmail(any(Email.class));
}
}
Explanation
Creating Mocks with
@Mock:- The
@Mockannotation creates a mock instance of theEmailServiceinterface. This mock instance can be used to simulate the behavior of theEmailServicein a controlled way.
- The
Injecting Mocks with
@InjectMocks:- The
@InjectMocksannotation injects the mockEmailServiceinto theNotificationServiceinstance to provide a controlled test environment. This allows theNotificationServicemethods to be tested in isolation from the actualEmailServiceimplementation.
- The
Mocking Void Methods:
doNothing(): ThedoNothing().when(emailService).sendEmail(any(Email.class));method configures the mockEmailServiceto do nothing when thesendEmailmethod is called with anyEmailobject.doThrow(): ThedoThrow(new RuntimeException("Email service is down")).when(emailService).sendEmail(any(Email.class));method configures the mockEmailServiceto throw aRuntimeExceptionwhen thesendEmailmethod is called with anyEmailobject.doAnswer(): ThedoAnswer(invocation -> { ... }).when(emailService).sendEmail(any(Email.class));method configures the mockEmailServiceto execute custom behavior when thesendEmailmethod is called with anyEmailobject.doCallRealMethod(): ThedoCallRealMethod().when(emailService).sendEmail(any(Email.class));method configures the mockEmailServiceto call the real method implementation when thesendEmailmethod is called with anyEmailobject.
Additional Scenarios
Scenario: Mocking Void Methods with Custom Behavior and Call Count
In this scenario, we will demonstrate how to mock a void method with custom behavior and verify the call count using ArgumentMatchers.
@Test
public void testSendNotificationWithCustomBehaviorAndCallCount() {
// Given
String recipient = "test@example.com";
String message = "Hello, World!";
// Mock void method with custom behavior
doAnswer(invocation -> {
Email email = invocation.getArgument(0);
assertEquals("test@example.com", email.getRecipient());
assertEquals("Hello, World!", email.getMessage());
return null;
}).when(emailService).sendEmail(any(Email.class));
// When
notificationService.sendNotification(recipient, message);
notificationService.sendNotification(recipient, message);
// Then
verify(emailService, times(2)).sendEmail(any(Email.class));
}
Explanation
- Mocking Void Method with Custom Behavior and Call Count:
- The
doAnswer(invocation -> { ... }).when(emailService).sendEmail(any(Email.class));method configures the mockEmailServiceto execute custom behavior when thesendEmailmethod is called with anyEmailobject. - The
verify(emailService, times(2)).sendEmail(any(Email.class));method checks if thesendEmailmethod was called on theEmailServiceexactly twice with anyEmailobject.
- The
Conclusion
Mocking void methods in Mockito simplifies the configuration of method calls on mock objects for unit testing. By using doNothing(), doThrow(), doAnswer(), and doCallRealMethod(), you can handle various scenarios and control the behavior of void methods. This step-by-step guide demonstrated how to effectively mock void methods in your unit tests, covering different scenarios to ensure comprehensive testing of the NotificationService class.
Comments
Post a Comment
Leave Comment