or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-testing.mdcore-testing.mdindex.mdjson-testing.mdmock-integration.mdoutput-capture.mdtest-slices.mdweb-testing.md

output-capture.mddocs/

0

# Output Capture

1

2

Console output testing utilities for capturing and asserting on system output during tests, providing comprehensive testing of application logging and console output.

3

4

## Capabilities

5

6

### Captured Output Interface

7

8

Interface for accessing captured console output from tests.

9

10

```java { .api }

11

/**

12

* Interface for captured output from System.out and System.err

13

* @since 2.2.0

14

*/

15

public interface CapturedOutput {

16

17

/**

18

* Get the captured output written to System.out

19

*/

20

String getOut();

21

22

/**

23

* Get the captured output written to System.err

24

*/

25

String getErr();

26

27

/**

28

* Get all captured output (both out and err combined)

29

*/

30

String getAll();

31

32

/**

33

* String representation of all captured output

34

*/

35

@Override

36

String toString();

37

}

38

```

39

40

### JUnit Jupiter Extension

41

42

JUnit Jupiter extension for output capture integration.

43

44

```java { .api }

45

/**

46

* JUnit Jupiter extension for capturing System.out and System.err output

47

* @since 2.2.0

48

*/

49

public class OutputCaptureExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {

50

51

/**

52

* Set up output capture before each test method

53

*/

54

@Override

55

public void beforeEach(ExtensionContext context) throws Exception;

56

57

/**

58

* Clean up output capture after each test method

59

*/

60

@Override

61

public void afterEach(ExtensionContext context) throws Exception;

62

63

/**

64

* Resolve CapturedOutput parameter for test methods

65

*/

66

@Override

67

public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext);

68

69

/**

70

* Provide CapturedOutput instance for test methods

71

*/

72

@Override

73

public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext);

74

}

75

```

76

77

**Usage Examples:**

78

79

```java

80

@ExtendWith(OutputCaptureExtension.class)

81

class OutputCaptureJupiterTest {

82

83

@Test

84

void captureOutput(CapturedOutput output) {

85

System.out.println("Hello World");

86

System.err.println("Error message");

87

88

assertThat(output.getOut()).contains("Hello World");

89

assertThat(output.getErr()).contains("Error message");

90

assertThat(output.getAll()).contains("Hello World", "Error message");

91

}

92

93

@Test

94

void captureLoggingOutput(CapturedOutput output) {

95

Logger logger = LoggerFactory.getLogger(OutputCaptureJupiterTest.class);

96

logger.info("This is an info message");

97

logger.warn("This is a warning message");

98

logger.error("This is an error message");

99

100

assertThat(output.getAll())

101

.contains("This is an info message")

102

.contains("This is a warning message")

103

.contains("This is an error message");

104

}

105

106

@Test

107

void captureSystemPropertyOutput(CapturedOutput output) {

108

System.setProperty("test.property", "test-value");

109

System.out.println("Property value: " + System.getProperty("test.property"));

110

111

assertThat(output.getOut()).contains("Property value: test-value");

112

}

113

}

114

```

115

116

### JUnit 4 Rule

117

118

JUnit 4 rule for output capture (for legacy test support).

119

120

```java { .api }

121

/**

122

* JUnit 4 rule for capturing System.out and System.err output

123

* @since 1.4.0

124

*/

125

public class OutputCaptureRule implements TestRule {

126

127

/**

128

* Create an OutputCaptureRule

129

*/

130

public OutputCaptureRule();

131

132

/**

133

* Apply the rule to the given test

134

*/

135

@Override

136

public Statement apply(Statement base, Description description);

137

138

/**

139

* Get the captured output written to System.out

140

*/

141

public String getOut();

142

143

/**

144

* Get the captured output written to System.err

145

*/

146

public String getErr();

147

148

/**

149

* Get all captured output (both out and err combined)

150

*/

151

public String getAll();

152

153

/**

154

* String representation of all captured output

155

*/

156

@Override

157

public String toString();

158

}

159

```

160

161

**Usage Examples:**

162

163

```java

164

public class OutputCaptureRuleTest {

165

166

@Rule

167

public OutputCaptureRule output = new OutputCaptureRule();

168

169

@Test

170

public void captureOutput() {

171

System.out.println("Hello from JUnit 4");

172

System.err.println("Error from JUnit 4");

173

174

assertThat(output.getOut()).contains("Hello from JUnit 4");

175

assertThat(output.getErr()).contains("Error from JUnit 4");

176

assertThat(output.getAll()).contains("Hello from JUnit 4", "Error from JUnit 4");

177

}

178

}

179

```

180

181

### Integration with Spring Boot Tests

182

183

Output capture integration with Spring Boot testing annotations.

184

185

**Usage Examples:**

186

187

```java

188

@SpringBootTest

189

@ExtendWith(OutputCaptureExtension.class)

190

class SpringBootOutputCaptureTest {

191

192

@Autowired

193

private MyService myService;

194

195

@Test

196

void captureServiceOutput(CapturedOutput output) {

197

myService.performAction();

198

199

assertThat(output.getAll())

200

.contains("Service action started")

201

.contains("Service action completed");

202

}

203

204

@Test

205

void captureStartupOutput(CapturedOutput output) {

206

// Output capture will include Spring Boot startup messages

207

assertThat(output.getAll())

208

.contains("Started SpringBootOutputCaptureTest")

209

.contains("Spring Boot");

210

}

211

}

212

213

@WebMvcTest(UserController.class)

214

@ExtendWith(OutputCaptureExtension.class)

215

class WebMvcOutputCaptureTest {

216

217

@Autowired

218

private MockMvc mockMvc;

219

220

@MockBean

221

private UserService userService;

222

223

@Test

224

void captureControllerOutput(CapturedOutput output) throws Exception {

225

when(userService.findByEmail("test@example.com"))

226

.thenReturn(new User("test@example.com", "Test User"));

227

228

mockMvc.perform(get("/users/test@example.com"))

229

.andExpect(status().isOk());

230

231

// Verify that controller logging is captured

232

assertThat(output.getAll()).contains("Processing user request");

233

}

234

}

235

```

236

237

### Advanced Output Capture Patterns

238

239

Advanced patterns for testing complex output scenarios.

240

241

**Usage Examples:**

242

243

```java

244

@ExtendWith(OutputCaptureExtension.class)

245

class AdvancedOutputCaptureTest {

246

247

@Test

248

void captureMultiThreadedOutput(CapturedOutput output) throws InterruptedException {

249

ExecutorService executor = Executors.newFixedThreadPool(3);

250

CountDownLatch latch = new CountDownLatch(3);

251

252

for (int i = 0; i < 3; i++) {

253

final int threadNum = i;

254

executor.submit(() -> {

255

try {

256

System.out.println("Thread " + threadNum + " starting");

257

Thread.sleep(100);

258

System.out.println("Thread " + threadNum + " finished");

259

} catch (InterruptedException e) {

260

Thread.currentThread().interrupt();

261

} finally {

262

latch.countDown();

263

}

264

});

265

}

266

267

latch.await(5, TimeUnit.SECONDS);

268

executor.shutdown();

269

270

String allOutput = output.getAll();

271

assertThat(allOutput)

272

.contains("Thread 0 starting", "Thread 0 finished")

273

.contains("Thread 1 starting", "Thread 1 finished")

274

.contains("Thread 2 starting", "Thread 2 finished");

275

}

276

277

@Test

278

void captureExceptionOutput(CapturedOutput output) {

279

try {

280

throw new RuntimeException("Test exception with cause",

281

new IllegalArgumentException("Root cause"));

282

} catch (Exception e) {

283

e.printStackTrace();

284

}

285

286

String errOutput = output.getErr();

287

assertThat(errOutput)

288

.contains("RuntimeException: Test exception with cause")

289

.contains("Caused by: java.lang.IllegalArgumentException: Root cause")

290

.contains("at " + getClass().getName());

291

}

292

293

@Test

294

void captureProgressOutput(CapturedOutput output) {

295

System.out.print("Processing");

296

for (int i = 0; i < 5; i++) {

297

System.out.print(".");

298

try {

299

Thread.sleep(50);

300

} catch (InterruptedException e) {

301

Thread.currentThread().interrupt();

302

}

303

}

304

System.out.println(" Done!");

305

306

assertThat(output.getOut())

307

.contains("Processing.....")

308

.contains("Done!");

309

}

310

311

@Test

312

void captureFormattedOutput(CapturedOutput output) {

313

String name = "Alice";

314

int age = 30;

315

double salary = 75000.50;

316

317

System.out.printf("Employee: %s, Age: %d, Salary: $%.2f%n", name, age, salary);

318

System.out.println(String.format("Formatted data: [%10s] [%3d] [%10.2f]", name, age, salary));

319

320

assertThat(output.getOut())

321

.contains("Employee: Alice, Age: 30, Salary: $75000.50")

322

.contains("Formatted data: [ Alice] [ 30] [ 75000.50]");

323

}

324

325

@Test

326

void captureConditionalOutput(CapturedOutput output) {

327

boolean debugEnabled = true;

328

String operation = "data-processing";

329

330

System.out.println("Starting operation: " + operation);

331

332

if (debugEnabled) {

333

System.out.println("DEBUG: Operation details logged");

334

System.err.println("DEBUG: Memory usage checked");

335

}

336

337

System.out.println("Operation completed successfully");

338

339

assertThat(output.getOut())

340

.contains("Starting operation: data-processing")

341

.contains("DEBUG: Operation details logged")

342

.contains("Operation completed successfully");

343

344

assertThat(output.getErr())

345

.contains("DEBUG: Memory usage checked");

346

}

347

348

@Test

349

void captureNoOutput(CapturedOutput output) {

350

// Test that runs without producing any output

351

int result = 2 + 2;

352

353

assertThat(output.getOut()).isEmpty();

354

assertThat(output.getErr()).isEmpty();

355

assertThat(output.getAll()).isEmpty();

356

assertThat(result).isEqualTo(4);

357

}

358

359

@Test

360

void captureAndAnalyzeLogLevels(CapturedOutput output) {

361

Logger logger = LoggerFactory.getLogger("com.example.TestLogger");

362

363

logger.trace("This is a trace message");

364

logger.debug("This is a debug message");

365

logger.info("This is an info message");

366

logger.warn("This is a warning message");

367

logger.error("This is an error message");

368

369

String allOutput = output.getAll();

370

371

// Verify log levels are captured (depending on logging configuration)

372

assertThat(allOutput).contains("INFO");

373

assertThat(allOutput).contains("WARN");

374

assertThat(allOutput).contains("ERROR");

375

376

// Verify actual log messages

377

assertThat(allOutput)

378

.contains("This is an info message")

379

.contains("This is a warning message")

380

.contains("This is an error message");

381

}

382

}

383

384

// Example service that produces output for testing

385

@Service

386

static class MyService {

387

private static final Logger logger = LoggerFactory.getLogger(MyService.class);

388

389

public void performAction() {

390

logger.info("Service action started");

391

System.out.println("Performing business logic");

392

393

try {

394

Thread.sleep(100);

395

} catch (InterruptedException e) {

396

Thread.currentThread().interrupt();

397

}

398

399

logger.info("Service action completed");

400

System.out.println("Action finished successfully");

401

}

402

}

403

```

404

405

### Best Practices for Output Capture

406

407

Guidelines for effective output capture testing:

408

409

1. **Test Specific Output**: Focus on testing specific, meaningful output rather than implementation details

410

2. **Use Appropriate Assertions**: Use `contains()` for partial matches, `isEqualTo()` for exact matches

411

3. **Handle Timing**: Be aware of timing issues in multi-threaded scenarios

412

4. **Separate Concerns**: Test output separately from business logic when possible

413

5. **Consider Log Levels**: Remember that captured output depends on logging configuration

414

415

**Usage Examples:**

416

417

```java

418

@ExtendWith(OutputCaptureExtension.class)

419

class OutputCaptureBestPracticesTest {

420

421

@Test

422

void testSpecificBusinessOutput(CapturedOutput output) {

423

BusinessService service = new BusinessService();

424

service.processOrder("ORDER-123");

425

426

// Test specific business-relevant output

427

assertThat(output.getAll())

428

.contains("Processing order: ORDER-123")

429

.contains("Order processed successfully");

430

}

431

432

@Test

433

void testErrorScenarioOutput(CapturedOutput output) {

434

BusinessService service = new BusinessService();

435

436

assertThatThrownBy(() -> service.processOrder(null))

437

.isInstanceOf(IllegalArgumentException.class);

438

439

// Verify error logging

440

assertThat(output.getErr())

441

.contains("Invalid order ID: null");

442

}

443

444

@Test

445

void testOutputWithRegex(CapturedOutput output) {

446

BusinessService service = new BusinessService();

447

service.generateReport();

448

449

// Use regex for flexible matching

450

assertThat(output.getAll())

451

.containsPattern("Report generated at \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")

452

.containsPattern("Total records: \\d+");

453

}

454

}

455

```