Mockito BDDMockito willCallRealMethod()

Introduction

BDDMockito.willCallRealMethod() 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 call the real method implementation. This is particularly useful when you want to test the actual behavior of a method while still being able to mock other methods in the same class. This tutorial will demonstrate how to use BDDMockito.willCallRealMethod() to call real 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 CalculatorService class that has a dependency on a MathService. Our goal is to test the CalculatorService methods using BDDMockito.willCallRealMethod() to call the real methods.

CalculatorService and MathService Classes

First, create the MathService class and the CalculatorService class.

public class MathService {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }
}

public class CalculatorService {
    private final MathService mathService;

    public CalculatorService(MathService mathService) {
        this.mathService = mathService;
    }

    public int addNumbers(int a, int b) {
        return mathService.add(a, b);
    }

    public int subtractNumbers(int a, int b) {
        return mathService.subtract(a, b);
    }
}

JUnit 5 Test Class with BDDMockito

Create a test class for CalculatorService 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 CalculatorServiceTest {

    @Mock
    private MathService mathService;

    @InjectMocks
    private CalculatorService calculatorService;

    @Test
    public void testAddNumbersCallsRealMethod() {
        // Given
        willCallRealMethod().given(mathService).add(anyInt(), anyInt());

        // When
        int result = calculatorService.addNumbers(5, 3);

        // Then
        assertEquals(8, result);
        then(mathService).should().add(5, 3);
    }

    @Test
    public void testSubtractNumbersCallsRealMethod() {
        // Given
        willCallRealMethod().given(mathService).subtract(anyInt(), anyInt());

        // When
        int result = calculatorService.subtractNumbers(10, 4);

        // Then
        assertEquals(6, result);
        then(mathService).should().subtract(10, 4);
    }
}

Explanation

  1. Creating Mocks with @Mock:

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

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

    • willCallRealMethod(): The willCallRealMethod().given(mathService).add(anyInt(), anyInt()); method configures the mock MathService to call the real add method when it is called with any integer arguments. This allows the addNumbers method of the CalculatorService class to be tested with the real behavior of the add method.
    • Similarly, the willCallRealMethod().given(mathService).subtract(anyInt(), anyInt()); method configures the mock MathService to call the real subtract method when it is called with any integer arguments. This allows the subtractNumbers method of the CalculatorService class to be tested with the real behavior of the subtract method.
  4. Verifying Interactions:

    • The then(mathService).should().add(5, 3); and then(mathService).should().subtract(10, 4); methods verify that the add and subtract methods were called on the MathService with the specified arguments. This ensures that the addNumbers and subtractNumbers methods of the CalculatorService class interact with the MathService correctly.

Additional Scenarios

Scenario: Combining Real and Mocked Methods

In this scenario, we will demonstrate how to combine real and mocked methods using BDDMockito.willCallRealMethod().

@Test
public void testAddAndSubtractNumbers() {
    // Given
    willCallRealMethod().given(mathService).add(anyInt(), anyInt());
    given(mathService.subtract(anyInt(), anyInt())).willReturn(3);

    // When
    int addResult = calculatorService.addNumbers(5, 3);
    int subtractResult = calculatorService.subtractNumbers(10, 7);

    // Then
    assertEquals(8, addResult);
    assertEquals(3, subtractResult);
    then(mathService).should().add(5, 3);
    then(mathService).should().subtract(10, 7);
}

Explanation

  1. Combining Real and Mocked Methods:
    • The willCallRealMethod().given(mathService).add(anyInt(), anyInt()); method configures the mock MathService to call the real add method when it is called with any integer arguments.
    • The given(mathService.subtract(anyInt(), anyInt())).willReturn(3); method configures the mock MathService to return 3 when the subtract method is called with any integer arguments. This allows the addNumbers and subtractNumbers methods of the CalculatorService class to be tested with both real and mocked behaviors.

Conclusion

Using BDDMockito.willCallRealMethod() in Mockito allows you to write more readable and expressive tests that follow the Behavior-Driven Development (BDD) style. By using willCallRealMethod() for calling real methods, you can handle various scenarios and control the behavior of mock objects. This step-by-step guide demonstrated how to effectively use BDDMockito.willCallRealMethod() in your unit tests, covering different scenarios to ensure comprehensive testing of the CalculatorService 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