or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdargument-capturing.mdbdd-testing.mdindex.mdjunit-integration.mdmatchers.mdmock-creation.mdstubbing.mdverification.md

argument-capturing.mddocs/

0

# Argument Capturing

1

2

ArgumentCaptor allows you to capture arguments passed to mock methods during verification. This is useful for making detailed assertions on complex objects or when you need to inspect the actual values passed to mocks.

3

4

## Basic Argument Capturing

5

6

### ArgumentCaptor Class

7

8

```java { .api }

9

public class ArgumentCaptor<T> {

10

public static <T> ArgumentCaptor<T> forClass(Class<T> clazz);

11

public T capture();

12

public T getValue();

13

public List<T> getAllValues();

14

}

15

```

16

17

### Creating ArgumentCaptors

18

19

```java

20

// Programmatic creation

21

ArgumentCaptor<String> stringCaptor = ArgumentCaptor.forClass(String.class);

22

ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);

23

24

// Annotation-based creation (recommended)

25

@Captor

26

private ArgumentCaptor<String> stringCaptor;

27

28

@Captor

29

private ArgumentCaptor<User> userCaptor;

30

```

31

32

## Single Value Capturing

33

34

### Basic Usage

35

36

```java

37

@Mock

38

private EmailService emailService;

39

40

@Captor

41

private ArgumentCaptor<String> emailCaptor;

42

43

@Test

44

public void testEmailSending() {

45

UserService userService = new UserService(emailService);

46

47

// Execute the code under test

48

userService.registerUser("john@example.com", "John Doe");

49

50

// Capture the argument

51

verify(emailService).sendEmail(emailCaptor.capture());

52

53

// Assert on captured value

54

String capturedEmail = emailCaptor.getValue();

55

assertEquals("john@example.com", capturedEmail);

56

}

57

```

58

59

### Capturing Complex Objects

60

61

```java

62

@Mock

63

private UserRepository repository;

64

65

@Captor

66

private ArgumentCaptor<User> userCaptor;

67

68

@Test

69

public void testUserCreation() {

70

UserService service = new UserService(repository);

71

72

// Execute

73

service.createUser("John", "john@example.com", 25);

74

75

// Capture and verify

76

verify(repository).save(userCaptor.capture());

77

User capturedUser = userCaptor.getValue();

78

79

assertEquals("John", capturedUser.getName());

80

assertEquals("john@example.com", capturedUser.getEmail());

81

assertEquals(25, capturedUser.getAge());

82

}

83

```

84

85

## Multiple Value Capturing

86

87

### Capturing Multiple Invocations

88

89

```java

90

@Mock

91

private Logger logger;

92

93

@Captor

94

private ArgumentCaptor<String> messageCaptor;

95

96

@Test

97

public void testMultipleLogEntries() {

98

Service service = new Service(logger);

99

100

// Execute multiple operations that log

101

service.processItems(Arrays.asList("item1", "item2", "item3"));

102

103

// Capture all log messages

104

verify(logger, times(3)).log(messageCaptor.capture());

105

List<String> capturedMessages = messageCaptor.getAllValues();

106

107

assertEquals(3, capturedMessages.size());

108

assertEquals("Processing item1", capturedMessages.get(0));

109

assertEquals("Processing item2", capturedMessages.get(1));

110

assertEquals("Processing item3", capturedMessages.get(2));

111

}

112

```

113

114

### Capturing Varargs

115

116

```java

117

@Mock

118

private EventPublisher publisher;

119

120

@Captor

121

private ArgumentCaptor<Event> eventCaptor;

122

123

@Test

124

public void testEventPublishing() {

125

Service service = new Service(publisher);

126

127

// Method that publishes multiple events via varargs

128

service.processTransaction();

129

130

// Capture varargs

131

verify(publisher).publish(eventCaptor.capture());

132

List<Event> capturedEvents = eventCaptor.getAllValues();

133

134

assertEquals(2, capturedEvents.size());

135

assertTrue(capturedEvents.get(0) instanceof TransactionStartedEvent);

136

assertTrue(capturedEvents.get(1) instanceof TransactionCompletedEvent);

137

}

138

```

139

140

## Advanced Capturing Patterns

141

142

### Capturing with Verification Modes

143

144

```java

145

@Mock

146

private AuditService auditService;

147

148

@Captor

149

private ArgumentCaptor<AuditEvent> auditCaptor;

150

151

@Test

152

public void testAuditingWithTimeout() {

153

AsyncService service = new AsyncService(auditService);

154

155

// Execute async operation

156

service.performAsyncOperation();

157

158

// Capture with timeout for async operations

159

verify(auditService, timeout(1000)).logEvent(auditCaptor.capture());

160

AuditEvent capturedEvent = auditCaptor.getValue();

161

162

assertNotNull(capturedEvent);

163

assertEquals("ASYNC_OPERATION", capturedEvent.getType());

164

}

165

```

166

167

### Capturing Multiple Arguments

168

169

```java

170

@Mock

171

private NotificationService notificationService;

172

173

@Captor

174

private ArgumentCaptor<String> recipientCaptor;

175

176

@Captor

177

private ArgumentCaptor<String> messageCaptor;

178

179

@Test

180

public void testNotificationSending() {

181

Service service = new Service(notificationService);

182

183

service.sendNotification("user@example.com", "Your order is ready");

184

185

verify(notificationService).send(recipientCaptor.capture(), messageCaptor.capture());

186

187

assertEquals("user@example.com", recipientCaptor.getValue());

188

assertEquals("Your order is ready", messageCaptor.getValue());

189

}

190

```

191

192

### Capturing in Ordered Verification

193

194

```java

195

@Mock

196

private DatabaseService database;

197

198

@Mock

199

private CacheService cache;

200

201

@Captor

202

private ArgumentCaptor<String> dbKeyCaptor;

203

204

@Captor

205

private ArgumentCaptor<String> cacheKeyCaptor;

206

207

@Test

208

public void testOrderedOperations() {

209

Service service = new Service(database, cache);

210

211

service.updateData("key123", "newValue");

212

213

InOrder inOrder = inOrder(database, cache);

214

inOrder.verify(database).update(dbKeyCaptor.capture(), any());

215

inOrder.verify(cache).invalidate(cacheKeyCaptor.capture());

216

217

assertEquals("key123", dbKeyCaptor.getValue());

218

assertEquals("key123", cacheKeyCaptor.getValue());

219

}

220

```

221

222

## Generic Type Capturing

223

224

### Capturing Generic Collections

225

226

```java

227

@Mock

228

private DataProcessor processor;

229

230

@Captor

231

private ArgumentCaptor<List<String>> listCaptor;

232

233

@Captor

234

private ArgumentCaptor<Map<String, Object>> mapCaptor;

235

236

@Test

237

public void testGenericCapturing() {

238

Service service = new Service(processor);

239

240

service.processData();

241

242

verify(processor).process(listCaptor.capture(), mapCaptor.capture());

243

244

List<String> capturedList = listCaptor.getValue();

245

Map<String, Object> capturedMap = mapCaptor.getValue();

246

247

assertFalse(capturedList.isEmpty());

248

assertTrue(capturedMap.containsKey("timestamp"));

249

}

250

```

251

252

### Capturing with Wildcards

253

254

```java

255

// For methods that accept wildcard generics

256

@Captor

257

private ArgumentCaptor<List<? extends Serializable>> wildcardCaptor;

258

259

@Test

260

public void testWildcardCapturing() {

261

verify(service).process(wildcardCaptor.capture());

262

List<? extends Serializable> captured = wildcardCaptor.getValue();

263

// Process captured list

264

}

265

```

266

267

## Integration with Matchers

268

269

### Capturing with Argument Matchers

270

271

```java

272

@Mock

273

private EmailService emailService;

274

275

@Captor

276

private ArgumentCaptor<EmailMessage> messageCaptor;

277

278

@Test

279

public void testEmailWithMatchers() {

280

service.sendEmail();

281

282

// Mix capturing with other matchers

283

verify(emailService).send(

284

messageCaptor.capture(),

285

eq(Priority.HIGH),

286

any(DeliveryOptions.class)

287

);

288

289

EmailMessage captured = messageCaptor.getValue();

290

assertEquals("Important Update", captured.getSubject());

291

}

292

```

293

294

### Conditional Capturing

295

296

```java

297

@Test

298

public void testConditionalCapturing() {

299

service.processRequests();

300

301

// Capture only for specific conditions

302

verify(processor).handle(argThat(request -> {

303

if (request.getPriority() == Priority.HIGH) {

304

// Additional verification logic

305

return true;

306

}

307

return false;

308

}));

309

}

310

```

311

312

## Best Practices

313

314

### When to Use ArgumentCaptor

315

316

**Good use cases:**

317

```java

318

// Complex object verification

319

verify(service).save(userCaptor.capture());

320

User user = userCaptor.getValue();

321

assertEquals("expected@email.com", user.getEmail());

322

323

// Multiple invocation analysis

324

verify(logger, times(3)).log(messageCaptor.capture());

325

List<String> messages = messageCaptor.getAllValues();

326

assertTrue(messages.contains("Expected log message"));

327

328

// Dynamic value verification

329

verify(service).schedule(taskCaptor.capture());

330

Task task = taskCaptor.getValue();

331

assertTrue(task.getScheduledTime().isAfter(Instant.now()));

332

```

333

334

**Avoid when simple matchers suffice:**

335

```java

336

// Unnecessary - use matchers instead

337

verify(service).process(stringCaptor.capture());

338

assertEquals("expected", stringCaptor.getValue());

339

340

// Better

341

verify(service).process(eq("expected"));

342

```

343

344

### Capturing vs Stubbing

345

346

**Use ArgumentCaptor for verification, not stubbing:**

347

348

```java

349

// WRONG - don't use captors in stubbing

350

when(service.process(captor.capture())).thenReturn("result");

351

352

// CORRECT - use captors in verification

353

verify(service).process(captor.capture());

354

String captured = captor.getValue();

355

```

356

357

### Error Handling

358

359

```java

360

@Test

361

public void testCaptorErrorHandling() {

362

// Verify method was called before getting value

363

verify(service).process(captor.capture());

364

365

// Safe to get value after verification

366

String captured = captor.getValue();

367

368

// Check for multiple values

369

if (captor.getAllValues().size() > 1) {

370

// Handle multiple captures

371

List<String> allValues = captor.getAllValues();

372

// Process all values

373

}

374

}

375

```

376

377

### Captor Naming

378

379

```java

380

// Good - descriptive names

381

@Captor private ArgumentCaptor<User> userCaptor;

382

@Captor private ArgumentCaptor<EmailMessage> emailMessageCaptor;

383

@Captor private ArgumentCaptor<AuditEvent> auditEventCaptor;

384

385

// Avoid - generic names

386

@Captor private ArgumentCaptor<Object> objectCaptor;

387

@Captor private ArgumentCaptor<String> captor1;

388

```

389

390

## Common Patterns

391

392

### Builder Pattern Verification

393

394

```java

395

@Captor

396

private ArgumentCaptor<QueryBuilder> queryCaptor;

397

398

@Test

399

public void testQueryBuilding() {

400

service.findUsers("active", "admin");

401

402

verify(repository).findBy(queryCaptor.capture());

403

QueryBuilder query = queryCaptor.getValue();

404

405

assertTrue(query.hasCondition("status", "active"));

406

assertTrue(query.hasCondition("role", "admin"));

407

}

408

```

409

410

### Event Verification

411

412

```java

413

@Captor

414

private ArgumentCaptor<DomainEvent> eventCaptor;

415

416

@Test

417

public void testEventPublishing() {

418

service.updateUser(userId, newData);

419

420

verify(eventPublisher).publish(eventCaptor.capture());

421

DomainEvent event = eventCaptor.getValue();

422

423

assertEquals("UserUpdated", event.getType());

424

assertEquals(userId, event.getAggregateId());

425

}

426

```

427

428

### Request/Response Validation

429

430

```java

431

@Captor

432

private ArgumentCaptor<HttpRequest> requestCaptor;

433

434

@Test

435

public void testHttpCall() {

436

service.callExternalApi();

437

438

verify(httpClient).execute(requestCaptor.capture());

439

HttpRequest request = requestCaptor.getValue();

440

441

assertEquals("POST", request.getMethod());

442

assertEquals("/api/users", request.getPath());

443

assertNotNull(request.getHeader("Authorization"));

444

}

445

```