0
# BDD-Style Testing
1
2
This section covers Behavior-Driven Development (BDD) style testing using Mockito's BDDMockito class, which provides given/when/then syntax for more readable tests.
3
4
## BDD Fundamentals
5
6
### BDD vs Traditional Mockito
7
8
BDD-style testing focuses on behavior specification using natural language patterns.
9
10
```java
11
// Traditional Mockito
12
when(userService.findUser("john")).thenReturn(johnUser);
13
verify(userService).findUser("john");
14
15
// BDD-style with BDDMockito
16
given(userService.findUser("john")).willReturn(johnUser);
17
then(userService).should().findUser("john");
18
```
19
20
### Core BDD Imports
21
22
```java { .api }
23
import static org.mockito.BDDMockito.*;
24
// This includes all BDD methods plus standard Mockito methods
25
```
26
27
## Given-When-Then Structure
28
29
### BDD Test Structure
30
31
Organize tests using the given/when/then pattern.
32
33
```java
34
@Test
35
void shouldCreateUserWhenValidDataProvided() {
36
// GIVEN - Set up test conditions
37
User inputUser = new User("john", "john@example.com");
38
User savedUser = new User("john", "john@example.com", 1L);
39
40
given(userRepository.save(any(User.class))).willReturn(savedUser);
41
given(emailService.isValidEmail(anyString())).willReturn(true);
42
43
// WHEN - Execute the behavior being tested
44
User result = userService.createUser(inputUser);
45
46
// THEN - Verify the outcomes
47
then(userRepository).should().save(inputUser);
48
then(emailService).should().isValidEmail("john@example.com");
49
assertThat(result.getId()).isEqualTo(1L);
50
}
51
```
52
53
## BDD Stubbing
54
55
### Given Methods
56
57
Configure mock behavior using given() instead of when().
58
59
```java { .api }
60
public static <T> BDDMyOngoingStubbing<T> given(T methodCall)
61
62
interface BDDMyOngoingStubbing<T> {
63
BDDMyOngoingStubbing<T> willReturn(T value);
64
BDDMyOngoingStubbing<T> willReturn(T value, T... values);
65
BDDMyOngoingStubbing<T> willThrow(Throwable... throwables);
66
BDDMyOngoingStubbing<T> willThrow(Class<? extends Throwable> throwableType);
67
BDDMyOngoingStubbing<T> willAnswer(Answer<?> answer);
68
BDDMyOngoingStubbing<T> willCallRealMethod();
69
BDDMyOngoingStubbing<T> willDoNothing();
70
T getMock();
71
}
72
```
73
74
**Usage Examples:**
75
76
```java
77
@Test
78
void shouldHandleUserCreationScenarios() {
79
// GIVEN successful validation
80
given(validationService.validateUser(any(User.class)))
81
.willReturn(ValidationResult.SUCCESS);
82
83
// GIVEN repository will save and return user with ID
84
given(userRepository.save(any(User.class)))
85
.willReturn(userWithId);
86
87
// GIVEN email service will send welcome email
88
given(emailService.sendWelcomeEmail(any(User.class)))
89
.willReturn(true);
90
91
// WHEN creating user
92
CreateUserResult result = userService.createUser(newUserData);
93
94
// THEN all collaborators should be called appropriately
95
then(validationService).should().validateUser(any(User.class));
96
then(userRepository).should().save(any(User.class));
97
then(emailService).should().sendWelcomeEmail(any(User.class));
98
}
99
```
100
101
### Will-Methods for Stubbing
102
103
BDD alternatives to doXxx() methods.
104
105
```java { .api }
106
public static BDDStubber willReturn(Object toBeReturned)
107
public static BDDStubber willReturn(Object toBeReturned, Object... toBeReturnedNext)
108
public static BDDStubber willThrow(Throwable... toBeThrown)
109
public static BDDStubber willThrow(Class<? extends Throwable> throwableType)
110
public static BDDStubber willAnswer(Answer<?> answer)
111
public static BDDStubber willDoNothing()
112
public static BDDStubber willCallRealMethod()
113
114
interface BDDStubber {
115
<T> T given(T mock);
116
}
117
```
118
119
**Usage Examples:**
120
121
```java
122
@Test
123
void shouldHandleEmailServiceFailures() {
124
// GIVEN email service will fail on first call, succeed on second
125
willThrow(EmailException.class)
126
.willReturn(true)
127
.given(emailService).sendEmail(anyString());
128
129
// GIVEN notification service will do nothing when called
130
willDoNothing().given(notificationService).notifyAdmin(anyString());
131
132
// WHEN processing with retry logic
133
boolean result = emailProcessor.sendWithRetry("message");
134
135
// THEN service should retry and eventually succeed
136
then(emailService).should(times(2)).sendEmail("message");
137
then(notificationService).should().notifyAdmin("Email failed on first attempt");
138
assertTrue(result);
139
}
140
```
141
142
## BDD Verification
143
144
### Then-Should Pattern
145
146
Verify interactions using then().should() syntax.
147
148
```java { .api }
149
public static <T> Then<T> then(T mock)
150
151
interface Then<T> {
152
BDDInOrder<T> should();
153
BDDInOrder<T> should(VerificationMode mode);
154
BDDInOrder<T> shouldHaveNoInteractions();
155
BDDInOrder<T> shouldHaveNoMoreInteractions();
156
BDDInOrder<T> shouldHaveZeroInteractions(); // Deprecated
157
}
158
```
159
160
**Usage Examples:**
161
162
```java
163
@Test
164
void shouldVerifyUserServiceInteractions() {
165
// GIVEN
166
given(userRepository.existsByEmail(anyString())).willReturn(false);
167
given(userRepository.save(any(User.class))).willReturn(savedUser);
168
169
// WHEN
170
userService.registerUser("john@example.com", "password");
171
172
// THEN - verify specific interactions
173
then(userRepository).should().existsByEmail("john@example.com");
174
then(userRepository).should().save(any(User.class));
175
then(emailService).should().sendWelcomeEmail(savedUser);
176
177
// THEN - verify no unexpected interactions
178
then(userRepository).shouldHaveNoMoreInteractions();
179
then(emailService).shouldHaveNoMoreInteractions();
180
}
181
182
@Test
183
void shouldVerifyInteractionCounts() {
184
// WHEN
185
for (int i = 0; i < 3; i++) {
186
cacheService.get("key" + i);
187
}
188
189
// THEN
190
then(cacheService).should(times(3)).get(anyString());
191
then(cacheService).should(never()).put(anyString(), any());
192
then(cacheService).should(atLeast(1)).get(startsWith("key"));
193
}
194
```
195
196
## BDD Ordered Verification
197
198
### InOrder BDD Style
199
200
Verify interaction order using BDD syntax.
201
202
```java { .api }
203
interface BDDInOrder<T> {
204
T should();
205
T should(VerificationMode mode);
206
void shouldHaveNoMoreInteractions();
207
}
208
```
209
210
**Usage Examples:**
211
212
```java
213
@Test
214
void shouldProcessPaymentInCorrectOrder() {
215
// GIVEN
216
given(paymentValidator.validate(any())).willReturn(true);
217
given(paymentGateway.charge(any())).willReturn(successResult);
218
given(orderService.updateStatus(any(), any())).willReturn(updatedOrder);
219
220
// WHEN
221
paymentProcessor.processPayment(payment);
222
223
// THEN - verify order of operations
224
InOrder inOrder = inOrder(paymentValidator, paymentGateway, orderService);
225
then(paymentValidator).should(inOrder).validate(payment);
226
then(paymentGateway).should(inOrder).charge(payment);
227
then(orderService).should(inOrder).updateStatus(payment.getOrderId(), PAID);
228
}
229
```
230
231
## Advanced BDD Patterns
232
233
### Scenario-Based Testing
234
235
Structure complex scenarios with clear BDD language.
236
237
```java
238
class OrderProcessingBDDTest {
239
240
@Test
241
void shouldCompleteOrderWhenPaymentSucceeds() {
242
// GIVEN an order with valid items
243
Order order = orderWithValidItems();
244
given(inventoryService.checkAvailability(any())).willReturn(true);
245
246
// AND payment processing will succeed
247
given(paymentService.processPayment(any())).willReturn(paymentSuccess());
248
249
// AND shipping service is available
250
given(shippingService.scheduleDelivery(any())).willReturn(deliveryScheduled());
251
252
// WHEN processing the order
253
OrderResult result = orderProcessor.processOrder(order);
254
255
// THEN inventory should be checked
256
then(inventoryService).should().checkAvailability(order.getItems());
257
258
// AND payment should be processed
259
then(paymentService).should().processPayment(order.getPayment());
260
261
// AND delivery should be scheduled
262
then(shippingService).should().scheduleDelivery(order);
263
264
// AND order should be completed successfully
265
assertThat(result.getStatus()).isEqualTo(OrderStatus.COMPLETED);
266
assertThat(result.getTrackingNumber()).isNotNull();
267
}
268
269
@Test
270
void shouldFailOrderWhenPaymentFails() {
271
// GIVEN an order with valid items
272
Order order = orderWithValidItems();
273
given(inventoryService.checkAvailability(any())).willReturn(true);
274
275
// BUT payment processing will fail
276
given(paymentService.processPayment(any()))
277
.willThrow(new PaymentFailedException("Insufficient funds"));
278
279
// WHEN processing the order
280
OrderResult result = orderProcessor.processOrder(order);
281
282
// THEN inventory should be checked
283
then(inventoryService).should().checkAvailability(order.getItems());
284
285
// AND payment should be attempted
286
then(paymentService).should().processPayment(order.getPayment());
287
288
// BUT shipping should not be attempted
289
then(shippingService).should(never()).scheduleDelivery(any());
290
291
// AND order should fail with appropriate status
292
assertThat(result.getStatus()).isEqualTo(OrderStatus.PAYMENT_FAILED);
293
assertThat(result.getError()).contains("Insufficient funds");
294
}
295
}
296
```
297
298
### Custom BDD Matchers
299
300
Create domain-specific matchers for more readable assertions.
301
302
```java
303
class CustomBDDMatchers {
304
305
public static ArgumentMatcher<User> validUser() {
306
return user -> user != null &&
307
user.getEmail() != null &&
308
user.getName() != null &&
309
user.getName().length() > 0;
310
}
311
312
public static ArgumentMatcher<Order> orderWithAmount(BigDecimal expectedAmount) {
313
return order -> order != null &&
314
order.getTotalAmount().equals(expectedAmount);
315
}
316
317
@Test
318
void shouldUseCustomMatchers() {
319
// GIVEN
320
given(userRepository.save(argThat(validUser()))).willReturn(savedUser);
321
322
// WHEN
323
userService.createUser("john", "john@example.com");
324
325
// THEN
326
then(userRepository).should().save(argThat(validUser()));
327
then(orderService).should().createOrder(argThat(orderWithAmount(new BigDecimal("99.99"))));
328
}
329
}
330
```
331
332
## BDD with Spies
333
334
### Behavioral Verification with Spies
335
336
Use BDD syntax with spies for partial mocking.
337
338
```java
339
@Test
340
void shouldCallRealMethodsSelectivelyWithSpy() {
341
// GIVEN a spy that calls real methods by default
342
UserService userServiceSpy = spy(new UserService(userRepository));
343
344
// BUT will return mock data for findUser
345
given(userServiceSpy.findUser(anyString())).willReturn(mockUser);
346
347
// WHEN calling updateUser (which internally calls findUser)
348
userServiceSpy.updateUser("john", updateData);
349
350
// THEN both real and mocked methods should be called appropriately
351
then(userServiceSpy).should().findUser("john"); // Mocked
352
then(userServiceSpy).should().updateUser("john", updateData); // Real method
353
then(userRepository).should().save(any(User.class)); // Real method called save
354
}
355
```