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?
- Readability → Tests read more like specifications.
- Consistency with BDD frameworks → Works well with tools like Cucumber.
- Clear separation of setup, action, and verification.
- 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
- Stick to Given-When-Then structure for clarity.
- Use descriptive method names → e.g.,
shouldReturnValidUserWhenUserExists()
. - Avoid overspecification → Verify only necessary interactions.
- Combine with JUnit 5 parameterized tests for broader coverage.
- 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.