Mockito BDDMockito any()

Introduction

BDDMockito.any() is a method provided by Mockito to support the Behavior-Driven Development (BDD) style of writing tests. It is used to match any argument of a specific type when verifying or stubbing method calls on mock objects. This is particularly useful when the specific value of the argument is not important for the test. This tutorial will demonstrate how to use BDDMockito.any() to handle flexible argument matching 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 UserService class that has a dependency on a UserRepository. Our goal is to test the UserService methods using BDDMockito.any() to handle flexible argument matching.

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(anyString())).willReturn(user);

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

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

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

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.
    • anyString(): The then(userRepository).should().findUserByEmail(anyString()); method verifies that the findUserByEmail method was called on the UserRepository with any String value.
    • given(): The given(userRepository.findUserByEmail(anyString())).willReturn(user); method configures the mock UserRepository to return a specific User object when the findUserByEmail method is called with any String value.
    • then(): The then(userRepository).should().findAllUsers(); method verifies that the findAllUsers method was called on the UserRepository.

Additional Scenarios

Scenario: Using Custom Matchers with BDDMockito

In this scenario, we will demonstrate how to use custom matchers with BDDMockito.any().

@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. Using Custom Matchers with BDDMockito:
    • 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. This allows the registerUser method of the UserService class to be tested with custom argument matchers.

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(anyString())).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(anyString());
}

Explanation

  1. Verifying Method Call Order:
    • The `InOrder inOrder

= inOrder(userRepository);statement creates anInOrderobject to verify the order of interactions with theUserRepositorymock object. - Thethen(userRepository).should(inOrder).saveUser(any(User.class));andthen(userRepository).should(inOrder).findUserByEmail(anyString());methods verify that thesaveUsermethod was called before thefindUserByEmailmethod on theUserRepository`.

Conclusion

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