Mockito timeout()

Introduction

The timeout() method in Mockito is used to verify that a specific method call on a mock object occurs within a given time frame. This is particularly useful when testing asynchronous code or ensuring that certain operations complete within an expected duration. This tutorial will demonstrate how to use the timeout() method in Mockito to handle timing-related verifications.

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 that the sendEmail method is called within a specified time frame using the timeout() method in Mockito.

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);
        new Thread(() -> emailService.sendEmail(email)).start();
    }
}

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 testSendNotificationWithTimeout() {
        // Given
        String recipient = "[email protected]";
        String message = "Hello, World!";

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

        // Then
        verify(emailService, timeout(1000)).sendEmail(any(Email.class));
    }

    @Test
    public void testSendNotificationWithTimeoutAndCount() {
        // Given
        String recipient = "[email protected]";
        String message = "Hello, World!";

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

        // Then
        verify(emailService, timeout(1000).times(2)).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. Verifying Method Call with timeout():

    • The verify(emailService, timeout(1000)).sendEmail(any(Email.class)); method checks if the sendEmail method was called on the EmailService within 1000 milliseconds. This ensures that the sendNotification method of the NotificationService class interacts with the EmailService in a timely manner.
  4. Verifying Method Call with timeout() and Call Count:

    • The verify(emailService, timeout(1000).times(2)).sendEmail(any(Email.class)); method checks if the sendEmail method was called on the EmailService within 1000 milliseconds and exactly twice. This ensures that the sendNotification method of the NotificationService class interacts with the EmailService the expected number of times within the given time frame.

Additional Scenarios

Scenario: Verifying Method Call with Timeout and Argument Matching

In this scenario, we will demonstrate how to verify a method call with a timeout and specific argument matching using the timeout() method.

@Test
public void testSendNotificationWithTimeoutAndArgumentMatching() {
    // Given
    String recipient = "[email protected]";
    String message = "Hello, World!";

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

    // Then
    verify(emailService, timeout(1000)).sendEmail(argThat(email -> email.getRecipient().equals(recipient) && email.getMessage().equals(message)));
}

Explanation

  1. Verifying Method Call with Timeout and Argument Matching:
    • The verify(emailService, timeout(1000)).sendEmail(argThat(email -> email.getRecipient().equals(recipient) && email.getMessage().equals(message))); method checks if the sendEmail method was called on the EmailService within 1000 milliseconds with an Email object that matches the specified recipient and message. This ensures that the sendNotification method of the NotificationService class interacts with the EmailService with the correct arguments within the given time frame.

Conclusion

The timeout() method in Mockito simplifies the verification of method calls on mock objects within a specific time frame for unit testing. By using timeout(), you can ensure that your code interacts with its dependencies in a timely manner. This step-by-step guide demonstrated how to effectively use the timeout() method in your unit tests, covering different scenarios to ensure comprehensive testing of the NotificationService 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