BDD Style with Mockito: given(), willReturn(), then()

Illustration for BDD Style with Mockito: given(), willReturn(), then()
By Last updated:

In modern software development, testing is not just about verifying outputs but also about expressing intent clearly. Behavior-Driven Development (BDD) promotes writing tests in a way that mirrors natural language specifications, making them more readable for developers, QA, and even business stakeholders.

Mockito, one of the most widely used Java mocking frameworks, supports a BDD style API with methods like given(), willReturn(), and then(). These methods provide a more natural, behavior-driven way of writing tests compared to the traditional when() and verify() approach.

In this tutorial, you’ll learn how to apply BDD style in Mockito to make your tests more expressive, readable, and maintainable.


What is BDD Style in Testing?

BDD (Behavior-Driven Development) is an evolution of TDD (Test-Driven Development). Instead of focusing on method inputs and outputs, BDD emphasizes system behavior in a human-readable format:

  • Given → Initial context or preconditions.
  • When → An action is performed.
  • Then → Expected outcome or verification.

Mockito aligns with this philosophy by providing given(), willReturn(), and then() methods.


Why Use BDD Style with Mockito?

  1. Readability → Tests read more like specifications.
  2. Consistency with BDD frameworks → Works well with tools like Cucumber.
  3. Clear separation of setup, action, and verification.
  4. Improved collaboration → Easier for non-developers to follow test logic.

Example: Traditional Mockito vs BDD Style

Traditional Mockito Test

import static org.mockito.Mockito.*;

@Test
void testGetUserName() {
    UserService userService = mock(UserService.class);
    when(userService.getUserName(1)).thenReturn("Alice");

    String result = userService.getUserName(1);

    verify(userService).getUserName(1);
    assertEquals("Alice", result);
}

BDD Style with Mockito

import static org.mockito.BDDMockito.*;
import static org.junit.jupiter.api.Assertions.*;

@Test
void testGetUserNameBDD() {
    // Given
    UserService userService = mock(UserService.class);
    given(userService.getUserName(1)).willReturn("Alice");

    // When
    String result = userService.getUserName(1);

    // Then
    then(userService).should().getUserName(1);
    assertEquals("Alice", result);
}

Notice how the BDD style test flows more naturally, aligning with the "Given-When-Then" mindset.


Core BDD Methods in Mockito

1. given()

Sets up expectations just like when().

given(userService.findUser("john")).willReturn(new User("john", "John Doe"));

2. willReturn()

Specifies the return value for the stubbed method.

given(userService.isActive("john")).willReturn(true);

3. then()

Verifies interactions, similar to verify().

then(userService).should(times(1)).findUser("john");

4. willThrow() for Exceptions

given(paymentService.charge(anyDouble())).willThrow(new RuntimeException("Insufficient balance"));

Advanced Usage

Stubbing with Multiple Return Values

given(calculator.add(1, 2)).willReturn(3, 5);

BDD Style with Argument Matchers

given(repository.save(any(User.class))).willReturn(new User("alex", "Alex Doe"));

BDD + Verify No More Interactions

then(service).should().process(anyString());
then(service).shouldHaveNoMoreInteractions();

Best Practices for BDD with Mockito

  1. Stick to Given-When-Then structure for clarity.
  2. Use descriptive method names → e.g., shouldReturnValidUserWhenUserExists().
  3. Avoid overspecification → Verify only necessary interactions.
  4. Combine with JUnit 5 parameterized tests for broader coverage.
  5. Leverage then().shouldHaveNoMoreInteractions() to catch unnecessary calls.

Case Study: Spring Boot Service Test with BDD

@SpringBootTest
class OrderServiceTest {

    @Mock
    private PaymentService paymentService;

    @InjectMocks
    private OrderService orderService;

    @Test
    void shouldPlaceOrderSuccessfullyWhenPaymentIsProcessed() {
        // Given
        given(paymentService.charge(100.0)).willReturn("TXN123");

        // When
        String result = orderService.placeOrder(100.0);

        // Then
        then(paymentService).should().charge(100.0);
        assertEquals("Order placed with transaction: TXN123", result);
    }
}

This example shows how BDD style makes the test case clear and self-explanatory.


Version Tracker

  • Mockito 1.x → BDD style was limited; most used when()/verify().
  • Mockito 2+ → Introduced BDDMockito API (given(), then()).
  • Mockito 3+ → Extended support for Java 11+ features and improved integration with JUnit 5.

Conclusion + Key Takeaways

  • BDD style in Mockito (given(), willReturn(), then()) improves readability and aligns with behavior-driven development.
  • Tests written in this style are easier to understand, maintain, and integrate into CI/CD pipelines.
  • Adopting BDD style with Mockito brings your unit tests closer to living documentation.

FAQ

1. What is the difference between when() and given() in Mockito?
They are functionally equivalent. given() is just a more BDD-friendly alias.

2. Can I mix when() and given() in the same test?
Yes, but it’s best practice to stick with one style for consistency.

3. How do I verify interactions in BDD style?
Use then(mock).should() instead of verify(mock).

4. Can I use given() with spies?
Yes, given() works with spies just like when().

5. Is BDDMockito a separate library?
No, it’s part of the core Mockito library.

6. How do I throw exceptions in BDD style?
Use willThrow() with given().

7. Can I use argument matchers with BDD style?
Yes, any(), eq(), and custom matchers work seamlessly.

8. Is BDD style compatible with JUnit 5?
Yes, BDDMockito integrates cleanly with JUnit 5.

9. Should I use BDD style in all tests?
It depends. Use it where readability and clarity are critical.

10. How does BDD style help in CI/CD?
It produces tests that double as living documentation, making failures more understandable.