Mockito BDDMockito times()

Introduction

BDDMockito.times() is a method provided by Mockito to support the Behavior-Driven Development (BDD) style of writing tests. It is used to verify the number of times a method was called on a mock object. This is particularly useful when you want to ensure that a method is called a specific number of times. This tutorial will demonstrate how to use BDDMockito.times() to verify the number of method calls 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.times() to verify the number of method calls.

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);
    }

    public void sendMultipleNotifications(String recipient, String message, int times) {
        for (int i = 0; i < times; i++) {
            sendNotification(recipient, message);
        }
    }
}

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(times(1)).sendEmail(any(Email.class));
    }

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

        // When
        notificationService.sendMultipleNotifications(recipient, message, times);

        // Then
        then(emailService).should(times(times)).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.
    • then(): The then(emailService).should(times(1)).sendEmail(any(Email.class)); method verifies that the sendEmail method was called on the EmailService exactly once. This ensures that the sendNotification method of the NotificationService class interacts with the EmailService correctly.
    • Similarly, the then(emailService).should(times(times)).sendEmail(any(Email.class)); method verifies that the sendEmail method was called on the EmailService the specified number of times.

Additional Scenarios

Scenario: Verifying No Interactions

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

@Test
public void testNoInteractionsWithEmailService() {
    // Given
    // No interactions expected

    // When
    // No method calls

    // Then
    then(emailService).shouldHaveNoInteractions();
}

Explanation

  1. Verifying No Interactions:
    • The then(emailService).shouldHaveNoInteractions(); method verifies that no interactions occurred with the EmailService mock object. This ensures that the EmailService was not used during the test.

Scenario: Verifying Method Call Order

In this scenario, we will demonstrate how to verify the order of method calls using BDDMockito.

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

    // When
    notificationService.sendNotification(recipient, message1);
    notificationService.sendNotification(recipient, message2);

    // Then
    InOrder inOrder = inOrder(emailService);
    then(emailService).should(inOrder).sendEmail(argThat(email -> email.getMessage().equals("Hello, World!")));
    then(emailService).should(inOrder).sendEmail(argThat(email -> email.getMessage().equals("Goodbye, World!")));
}

Explanation

  1. Verifying Method Call Order:
    • The InOrder inOrder = inOrder(emailService); statement creates an InOrder object to verify the order of interactions with the EmailService mock object.
    • The then(emailService).should(inOrder).sendEmail(argThat(email -> email.getMessage().equals("Hello, World!"))); and then(emailService).should(inOrder).sendEmail(argThat(email -> email.getMessage().equals("Goodbye, World!"))); methods verify that the sendEmail method was called with the specified messages in the correct order on the EmailService.

Conclusion

Using BDDMockito.times() in Mockito allows you to write more readable and expressive tests that follow the Behavior-Driven Development (BDD) style. By using times() for verifying the number of method calls, you can handle various scenarios and control the interactions with mock objects. This step-by-step guide demonstrated how to effectively use BDDMockito.times() 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