Mockito BDDMockito willDoNothing()

Introduction

BDDMockito.willDoNothing() is a method provided by Mockito to support the Behavior-Driven Development (BDD) style of writing tests. It is used to specify that a method call on a mock object should do nothing. This is particularly useful when you need to test void methods without any side effects or when you want to ignore certain method calls in your tests. This tutorial will demonstrate how to use BDDMockito.willDoNothing() to mock void methods in a BDD style.

Maven Dependencies

To use Mockito with JUnit 5 and enable BDDMockito syntax, 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 using BDDMockito.willDoNothing() to mock 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 BDDMockito

Create a test class for NotificationService using JUnit 5 and BDDMockito.

import static org.mockito.BDDMockito.*;
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 testSendNotification() {
        // Given
        String recipient = "test@example.com";
        String message = "Hello, World!";
        willDoNothing().given(emailService).sendEmail(any(Email.class));

        // When
        notificationService.sendNotification(recipient, message);

        // Then
        then(emailService).should().sendEmail(any(Email.class));
    }
}

Explanation

  1. Creating Mocks with @Mock:

    • The @Mock annotation creates a mock instance of the EmailService interface. This mock instance can be used to simulate the behavior of the EmailService in a controlled way.
  2. Injecting Mocks with @InjectMocks:

    • The @InjectMocks annotation injects the mock EmailService into the NotificationService instance to provide a controlled test environment. This allows the NotificationService methods to be tested in isolation from the actual EmailService implementation.
  3. Using BDDMockito:

    • willDoNothing(): The willDoNothing().given(emailService).sendEmail(any(Email.class)); method configures the mock EmailService to do nothing when the sendEmail method is called with any Email object. This allows the sendNotification method of the NotificationService class to be tested without side effects.
  4. Verifying Interactions:

    • The then(emailService).should().sendEmail(any(Email.class)); method verifies that the sendEmail method was called on the EmailService with any Email object. This ensures that the sendNotification method of the NotificationService class interacts with the EmailService correctly.

Additional Scenarios

Scenario: Verifying No More Interactions

In this scenario, we will demonstrate how to verify that no more interactions occurred with the mock object using BDDMockito.

@Test
public void testNoMoreInteractionsWithEmailService() {
    // Given
    String recipient = "test@example.com";
    String message = "Hello, World!";
    willDoNothing().given(emailService).sendEmail(any(Email.class));

    // When
    notificationService.sendNotification(recipient, message);

    // Then
    then(emailService).should().sendEmail(any(Email.class));
    then(emailService).shouldHaveNoMoreInteractions();
}

Explanation

  1. Verifying No More Interactions:
    • The then(emailService).shouldHaveNoMoreInteractions(); method verifies that no more interactions occurred with the EmailService mock object after the sendEmail method was called. This ensures that no unintended interactions happened with the EmailService.

Scenario: Handling Multiple Calls with BDDMockito

In this scenario, we will demonstrate how to handle multiple method calls using BDDMockito.willDoNothing().

@Test
public void testSendMultipleNotifications() {
    // Given
    String recipient1 = "test1@example.com";
    String message1 = "Hello, World!";
    String recipient2 = "test2@example.com";
    String message2 = "Goodbye, World!";
    willDoNothing().given(emailService).sendEmail(any(Email.class));

    // When
    notificationService.sendNotification(recipient1, message1);
    notificationService.sendNotification(recipient2, message2);

    // Then
    then(emailService).should(times(2)).sendEmail(any(Email.class));
}

Explanation

  1. Handling Multiple Calls with BDDMockito:
    • The then(emailService).should(times(2)).sendEmail(any(Email.class)); method verifies that the sendEmail method was called on the EmailService exactly twice with any Email object. This ensures that the sendNotification method of the NotificationService class interacts with the EmailService the expected number of times.

Conclusion

Using BDDMockito.willDoNothing() in Mockito allows you to write more readable and expressive tests that follow the Behavior-Driven Development (BDD) style. By using willDoNothing() for stubbing void methods, you can handle various scenarios and control the behavior of mock objects. This step-by-step guide demonstrated how to effectively use BDDMockito.willDoNothing() in your unit tests, covering different scenarios to ensure comprehensive testing of the NotificationService class.

Related Mockito BDDMockito Class Methods (Behavior-Driven Development Style)

Mockito BDDMockito
Mockito BDDMockito given()
Mockito BDDMockito willThrow()
Mockito BDDMockito willAnswer()
Mockito BDDMockito willReturn()
Mockito BDDMockito willDoNothing()
Mockito BDDMockito willCallRealMethod()
Mockito BDDMockito then()
Mockito BDDMockito.any()
Mockito BDDMockito.times()

Comments