or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

additional-answers.mdadditional-matchers.mdadvanced-features.mdannotations.mdargument-matching.mdbdd-testing.mdindex.mdmock-creation.mdstatic-mocking.mdstubbing.mdverification.md

bdd-testing.mddocs/

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

```