Mockito BDDMockito then()

Introduction

BDDMockito.then() is a method provided by Mockito to support the Behavior-Driven Development (BDD) style of writing tests. It is used to verify interactions with mock objects in a more readable and expressive way. This tutorial will demonstrate how to use BDDMockito.then() to verify method calls on mock objects.

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 UserService class that has a dependency on a UserRepository. Our goal is to test the UserService methods using BDDMockito.then() to verify method calls.

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);
    List<User> findAllUsers();
}

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

    public List<User> getAllUsers() {
        return userRepository.findAllUsers();
    }
}

JUnit 5 Test Class with BDDMockito

Create a test class for UserService 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;

import java.util.Arrays;
import java.util.List;

@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";

        // When
        userService.registerUser(name, email);

        // Then
        then(userRepository).should().saveUser(any(User.class));
    }

    @Test
    public void testGetUserByEmail() {
        // Given
        String email = "anita.patil@example.com";
        User user = new User("Anita Patil", email);
        given(userRepository.findUserByEmail(email)).willReturn(user);

        // When
        User result = userService.getUserByEmail(email);

        // Then
        assertNotNull(result);
        assertEquals("Anita Patil", result.getName());
        assertEquals(email, result.getEmail());
        then(userRepository).should().findUserByEmail(email);
    }

    @Test
    public void testGetAllUsers() {
        // Given
        User user1 = new User("Ravi Kumar", "ravi.kumar@example.com");
        User user2 = new User("Rajesh Verma", "rajesh.verma@example.com");
        List<User> users = Arrays.asList(user1, user2);
        given(userRepository.findAllUsers()).willReturn(users);

        // When
        List<User> result = userService.getAllUsers();

        // Then
        assertNotNull(result);
        assertEquals(2, result.size());
        assertEquals("Ravi Kumar", result.get(0).getName());
        assertEquals("Rajesh Verma", result.get(1).getName());
        then(userRepository).should().findAllUsers();
    }

    @Test
    public void testRegisterUserWithCustomMatcher() {
        // Given
        String name = "Anjali Sharma";
        String email = "anjali.sharma@example.com";

        // When
        userService.registerUser(name, email);

        // Then
        then(userRepository).should().saveUser(argThat(user -> user.getName().equals("Anjali Sharma") && user.getEmail().equals("anjali.sharma@example.com")));
    }
}

Explanation

  1. Creating Mocks with @Mock:

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

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

    • then(): The then(userRepository).should().saveUser(any(User.class)); method verifies that the saveUser method was called on the UserRepository with any User object. This allows the registerUser method of the UserService class to be tested with controlled interactions.
    • Similarly, the then(userRepository).should().findUserByEmail(email); and then(userRepository).should().findAllUsers(); methods verify that the respective methods were called on the UserRepository.
  4. Using Custom Matchers:

    • The then(userRepository).should().saveUser(argThat(user -> user.getName().equals("Anjali Sharma") && user.getEmail().equals("anjali.sharma@example.com"))); method verifies that the saveUser method was called on the UserRepository with a User object that matches the specified name and email.

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 testNoInteractionsWithUserRepository() {
    // Given
    // No interactions expected

    // When
    // No method calls

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

Explanation

  1. Verifying No Interactions:
    • The then(userRepository).shouldHaveNoInteractions(); method verifies that no interactions occurred with the UserRepository mock object. This ensures that the UserRepository 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 name = "Ramesh Fadatare";
    String email = "ramesh.fadatare@example.com";
    User user = new User(name, email);
    given(userRepository.findUserByEmail(email)).willReturn(user);

    // When
    userService.registerUser(name, email);
    userService.getUserByEmail(email);

    // Then
    InOrder inOrder = inOrder(userRepository);
    then(userRepository).should(inOrder).saveUser(any(User.class));
    then(userRepository).should(inOrder).findUserByEmail(email);
}

Explanation

  1. Verifying Method Call Order:
    • The InOrder inOrder = inOrder(userRepository); statement creates an InOrder object to verify the order of interactions with the UserRepository mock object.
    • The then(userRepository).should(inOrder).saveUser(any(User.class)); and then(userRepository).should(inOrder).findUserByEmail(email); methods verify that the saveUser method was called before the findUserByEmail method on the UserRepository.

Conclusion

Using BDDMockito.then() in Mockito allows you to write more readable and expressive tests that follow the Behavior-Driven Development (BDD) style. By using then() for verifying 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.then() in your unit tests, covering different scenarios to ensure comprehensive testing of the UserService 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