or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

conditional-testing.mdcore-testing.mdindex.mdmain-method-testing.mdmocking.mdtest-callbacks.mdtest-profiles.md

test-callbacks.mddocs/

0

# Test Callbacks

1

2

Quarkus JUnit 5 provides a comprehensive callback system through service provider interfaces that allow customization of test execution lifecycle at various phases.

3

4

## Callback Interfaces

5

6

### QuarkusTestBeforeEachCallback

7

8

Called before each test method in a `@QuarkusTest`.

9

10

```java { .api }

11

public interface QuarkusTestBeforeEachCallback {

12

void beforeEach(QuarkusTestMethodContext context);

13

}

14

```

15

16

### QuarkusTestAfterEachCallback

17

18

Called after each test method in a `@QuarkusTest`.

19

20

```java { .api }

21

public interface QuarkusTestAfterEachCallback {

22

void afterEach(QuarkusTestMethodContext context);

23

}

24

```

25

26

### QuarkusTestBeforeClassCallback

27

28

Called before the test class is executed.

29

30

```java { .api }

31

public interface QuarkusTestBeforeClassCallback {

32

void beforeClass(Class<?> testClass);

33

}

34

```

35

36

### QuarkusTestAfterAllCallback

37

38

Called after all tests in a test class have been executed.

39

40

```java { .api }

41

public interface QuarkusTestAfterAllCallback {

42

void afterAll(QuarkusTestContext context);

43

}

44

```

45

46

### QuarkusTestAfterConstructCallback

47

48

Called after the test instance has been constructed.

49

50

```java { .api }

51

public interface QuarkusTestAfterConstructCallback {

52

void afterConstruct(Object testInstance);

53

}

54

```

55

56

### QuarkusTestBeforeTestExecutionCallback

57

58

Called immediately before test method execution.

59

60

```java { .api }

61

public interface QuarkusTestBeforeTestExecutionCallback {

62

void beforeTestExecution(QuarkusTestMethodContext context);

63

}

64

```

65

66

### QuarkusTestAfterTestExecutionCallback

67

68

Called immediately after test method execution.

69

70

```java { .api }

71

public interface QuarkusTestAfterTestExecutionCallback {

72

void afterTestExecution(QuarkusTestMethodContext context);

73

}

74

```

75

76

## Context Classes

77

78

### QuarkusTestContext

79

80

Context object passed to test callbacks containing test execution information.

81

82

```java { .api }

83

public class QuarkusTestContext {

84

85

/**

86

* Get the test instance

87

*/

88

public Object getTestInstance();

89

90

/**

91

* Get outer test instances (for nested tests)

92

*/

93

public List<Object> getOuterInstances();

94

95

/**

96

* Get the test status including failure information

97

*/

98

public TestStatus getTestStatus();

99

}

100

```

101

102

### QuarkusTestMethodContext

103

104

Extended context for method-level callbacks, providing access to the test method.

105

106

```java { .api }

107

public final class QuarkusTestMethodContext extends QuarkusTestContext {

108

109

/**

110

* Get the test method being executed

111

*/

112

public Method getTestMethod();

113

}

114

```

115

116

## Service Provider Registration

117

118

Callback implementations must be registered as service providers in `META-INF/services/` files.

119

120

### Example Service Registration

121

122

Create file: `META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback`

123

124

```text

125

com.example.MyTestSetupCallback

126

com.example.DatabaseCleanupCallback

127

```

128

129

## Callback Implementation Examples

130

131

### Database Cleanup Callback

132

133

```java

134

import io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback;

135

import io.quarkus.test.junit.callback.QuarkusTestMethodContext;

136

import jakarta.enterprise.inject.spi.CDI;

137

import jakarta.persistence.EntityManager;

138

import jakarta.transaction.Transactional;

139

140

public class DatabaseCleanupCallback implements QuarkusTestAfterEachCallback {

141

142

@Override

143

public void afterEach(QuarkusTestMethodContext context) {

144

// Clean up database after each test

145

EntityManager em = CDI.current().select(EntityManager.class).get();

146

147

cleanupTestData(em);

148

}

149

150

@Transactional

151

private void cleanupTestData(EntityManager em) {

152

em.createQuery("DELETE FROM TestEntity").executeUpdate();

153

em.createQuery("DELETE FROM UserEntity WHERE email LIKE '%test%'").executeUpdate();

154

}

155

}

156

```

157

158

### Test Metrics Collector

159

160

```java

161

import io.quarkus.test.junit.callback.QuarkusTestBeforeTestExecutionCallback;

162

import io.quarkus.test.junit.callback.QuarkusTestAfterTestExecutionCallback;

163

import io.quarkus.test.junit.callback.QuarkusTestMethodContext;

164

import java.util.concurrent.ConcurrentHashMap;

165

import java.util.Map;

166

167

public class TestMetricsCallback implements

168

QuarkusTestBeforeTestExecutionCallback,

169

QuarkusTestAfterTestExecutionCallback {

170

171

private final Map<String, Long> testStartTimes = new ConcurrentHashMap<>();

172

private final Map<String, Long> testDurations = new ConcurrentHashMap<>();

173

174

@Override

175

public void beforeTestExecution(QuarkusTestMethodContext context) {

176

String testKey = getTestKey(context);

177

testStartTimes.put(testKey, System.currentTimeMillis());

178

System.out.println("Starting test: " + testKey);

179

}

180

181

@Override

182

public void afterTestExecution(QuarkusTestMethodContext context) {

183

String testKey = getTestKey(context);

184

Long startTime = testStartTimes.remove(testKey);

185

186

if (startTime != null) {

187

long duration = System.currentTimeMillis() - startTime;

188

testDurations.put(testKey, duration);

189

System.out.println("Test " + testKey + " took " + duration + "ms");

190

}

191

}

192

193

private String getTestKey(QuarkusTestMethodContext context) {

194

return context.getTestInstance().getClass().getSimpleName() +

195

"." + context.getTestMethod().getName();

196

}

197

}

198

```

199

200

### Mock Installation Callback

201

202

```java

203

import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback;

204

import io.quarkus.test.junit.callback.QuarkusTestMethodContext;

205

import io.quarkus.test.junit.QuarkusMock;

206

import org.mockito.Mockito;

207

import java.lang.reflect.Field;

208

209

public class AutoMockCallback implements QuarkusTestBeforeEachCallback {

210

211

@Override

212

public void beforeEach(QuarkusTestMethodContext context) {

213

Object testInstance = context.getTestInstance();

214

Class<?> testClass = testInstance.getClass();

215

216

// Find fields annotated with custom @MockBean annotation

217

for (Field field : testClass.getDeclaredFields()) {

218

if (field.isAnnotationPresent(MockBean.class)) {

219

installMockForField(field, testInstance);

220

}

221

}

222

}

223

224

private void installMockForField(Field field, Object testInstance) {

225

try {

226

field.setAccessible(true);

227

Object realBean = field.get(testInstance);

228

229

if (realBean != null) {

230

Object mock = Mockito.mock(field.getType());

231

QuarkusMock.installMockForInstance(mock, realBean);

232

233

// Replace field value with mock for easy access in tests

234

field.set(testInstance, mock);

235

}

236

} catch (Exception e) {

237

throw new RuntimeException("Failed to install mock for field: " + field.getName(), e);

238

}

239

}

240

}

241

242

// Custom annotation

243

@Retention(RetentionPolicy.RUNTIME)

244

@Target(ElementType.FIELD)

245

public @interface MockBean {

246

}

247

```

248

249

### Test Data Setup Callback

250

251

```java

252

import io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback;

253

import io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback;

254

import jakarta.enterprise.inject.spi.CDI;

255

import jakarta.persistence.EntityManager;

256

import jakarta.transaction.Transactional;

257

258

public class TestDataSetupCallback implements

259

QuarkusTestAfterConstructCallback,

260

QuarkusTestBeforeClassCallback {

261

262

@Override

263

public void beforeClass(Class<?> testClass) {

264

if (testClass.isAnnotationPresent(WithTestData.class)) {

265

setupTestData(testClass.getAnnotation(WithTestData.class));

266

}

267

}

268

269

@Override

270

public void afterConstruct(Object testInstance) {

271

Class<?> testClass = testInstance.getClass();

272

if (testClass.isAnnotationPresent(WithMethodTestData.class)) {

273

setupMethodSpecificData(testInstance);

274

}

275

}

276

277

@Transactional

278

void setupTestData(WithTestData annotation) {

279

EntityManager em = CDI.current().select(EntityManager.class).get();

280

281

for (String dataset : annotation.datasets()) {

282

loadDataset(em, dataset);

283

}

284

}

285

286

private void loadDataset(EntityManager em, String dataset) {

287

switch (dataset) {

288

case "users":

289

em.persist(new User("test1@example.com", "Test User 1"));

290

em.persist(new User("test2@example.com", "Test User 2"));

291

break;

292

case "products":

293

em.persist(new Product("Laptop", 999.99));

294

em.persist(new Product("Mouse", 29.99));

295

break;

296

}

297

}

298

299

private void setupMethodSpecificData(Object testInstance) {

300

// Setup data specific to individual test methods

301

}

302

}

303

304

// Custom annotations

305

@Retention(RetentionPolicy.RUNTIME)

306

@Target(ElementType.TYPE)

307

public @interface WithTestData {

308

String[] datasets() default {};

309

}

310

311

@Retention(RetentionPolicy.RUNTIME)

312

@Target(ElementType.TYPE)

313

public @interface WithMethodTestData {

314

String value() default "";

315

}

316

```

317

318

## Error Handling in Callbacks

319

320

### Safe Callback Implementation

321

322

```java

323

import io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback;

324

import io.quarkus.test.junit.callback.QuarkusTestMethodContext;

325

import org.slf4j.Logger;

326

import org.slf4j.LoggerFactory;

327

328

public class SafeCleanupCallback implements QuarkusTestAfterEachCallback {

329

330

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

331

332

@Override

333

public void afterEach(QuarkusTestMethodContext context) {

334

try {

335

performCleanup(context);

336

} catch (Exception e) {

337

// Log error but don't fail the test

338

logger.error("Cleanup failed for test: " +

339

context.getTestMethod().getName(), e);

340

}

341

}

342

343

private void performCleanup(QuarkusTestMethodContext context) {

344

// Cleanup logic that might fail

345

TestStatus status = context.getTestStatus();

346

if (status.getTestErrorCause() != null) {

347

// Special cleanup for failed tests

348

logger.info("Test failed, performing error cleanup");

349

}

350

}

351

}

352

```

353

354

### Context Information Usage

355

356

```java

357

import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback;

358

import io.quarkus.test.junit.callback.QuarkusTestMethodContext;

359

import java.lang.reflect.Method;

360

361

public class ContextAwareCallback implements QuarkusTestBeforeEachCallback {

362

363

@Override

364

public void beforeEach(QuarkusTestMethodContext context) {

365

Method testMethod = context.getTestMethod();

366

Object testInstance = context.getTestInstance();

367

368

// Check for custom test annotations

369

if (testMethod.isAnnotationPresent(SlowTest.class)) {

370

System.out.println("Starting slow test: " + testMethod.getName());

371

// Maybe increase timeout or adjust configuration

372

}

373

374

// Access test class information

375

Class<?> testClass = testInstance.getClass();

376

if (testClass.isAnnotationPresent(DatabaseTest.class)) {

377

// Setup database-specific configuration

378

setupDatabaseForTest();

379

}

380

381

// Check outer instances for nested tests

382

if (!context.getOuterInstances().isEmpty()) {

383

System.out.println("Running nested test in: " +

384

context.getOuterInstances().get(0).getClass().getSimpleName());

385

}

386

}

387

388

private void setupDatabaseForTest() {

389

// Database setup logic

390

}

391

}

392

393

@Retention(RetentionPolicy.RUNTIME)

394

@Target(ElementType.METHOD)

395

@interface SlowTest {

396

}

397

398

@Retention(RetentionPolicy.RUNTIME)

399

@Target(ElementType.TYPE)

400

@interface DatabaseTest {

401

}

402

```

403

404

## Advanced Callback Patterns

405

406

### Conditional Callback Execution

407

408

```java

409

import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback;

410

import io.quarkus.test.junit.callback.QuarkusTestMethodContext;

411

412

public class ConditionalCallback implements QuarkusTestBeforeEachCallback {

413

414

@Override

415

public void beforeEach(QuarkusTestMethodContext context) {

416

// Only execute for certain test classes

417

if (shouldExecuteForTest(context)) {

418

performSetup(context);

419

}

420

}

421

422

private boolean shouldExecuteForTest(QuarkusTestMethodContext context) {

423

Class<?> testClass = context.getTestInstance().getClass();

424

425

// Execute only for integration tests

426

return testClass.getPackage().getName().contains("integration");

427

}

428

429

private void performSetup(QuarkusTestMethodContext context) {

430

// Setup logic

431

}

432

}

433

```

434

435

### Resource Management Callback

436

437

```java

438

import io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback;

439

import io.quarkus.test.junit.callback.QuarkusTestAfterAllCallback;

440

import io.quarkus.test.junit.callback.QuarkusTestContext;

441

import java.util.concurrent.ConcurrentHashMap;

442

import java.util.Map;

443

444

public class ResourceManagerCallback implements

445

QuarkusTestBeforeClassCallback,

446

QuarkusTestAfterAllCallback {

447

448

private final Map<Class<?>, AutoCloseable> classResources = new ConcurrentHashMap<>();

449

450

@Override

451

public void beforeClass(Class<?> testClass) {

452

if (testClass.isAnnotationPresent(RequiresExternalService.class)) {

453

try {

454

ExternalServiceMock service = new ExternalServiceMock();

455

service.start();

456

classResources.put(testClass, service);

457

} catch (Exception e) {

458

throw new RuntimeException("Failed to start external service", e);

459

}

460

}

461

}

462

463

@Override

464

public void afterAll(QuarkusTestContext context) {

465

Class<?> testClass = context.getTestInstance().getClass();

466

AutoCloseable resource = classResources.remove(testClass);

467

468

if (resource != null) {

469

try {

470

resource.close();

471

} catch (Exception e) {

472

System.err.println("Failed to close resource: " + e.getMessage());

473

}

474

}

475

}

476

}

477

478

@Retention(RetentionPolicy.RUNTIME)

479

@Target(ElementType.TYPE)

480

@interface RequiresExternalService {

481

}

482

```

483

484

## Best Practices

485

486

### Service Provider Declaration

487

488

Always declare your callback implementations in the appropriate service files:

489

490

```text

491

# META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback

492

com.example.DatabaseCleanupCallback

493

com.example.TestMetricsCallback

494

495

# META-INF/services/io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback

496

com.example.AutoMockCallback

497

com.example.TestDataSetupCallback

498

```

499

500

### Error Handling

501

502

```java

503

public class RobustCallback implements QuarkusTestAfterEachCallback {

504

505

@Override

506

public void afterEach(QuarkusTestMethodContext context) {

507

try {

508

// Callback logic

509

performCleanup();

510

} catch (Exception e) {

511

// Never let callback exceptions fail tests

512

logError("Callback failed", e);

513

}

514

}

515

516

private void logError(String message, Exception e) {

517

// Use appropriate logging framework

518

System.err.println(message + ": " + e.getMessage());

519

}

520

}

521

```

522

523

### Performance Considerations

524

525

```java

526

public class EfficientCallback implements QuarkusTestBeforeEachCallback {

527

528

// Cache expensive resources

529

private static final Map<String, Object> cache = new ConcurrentHashMap<>();

530

531

@Override

532

public void beforeEach(QuarkusTestMethodContext context) {

533

String cacheKey = context.getTestMethod().getName();

534

535

// Use cached resources when possible

536

Object resource = cache.computeIfAbsent(cacheKey, this::createResource);

537

538

// Apply resource to test

539

applyResource(context, resource);

540

}

541

542

private Object createResource(String key) {

543

// Create expensive resource only once per test method

544

return new ExpensiveResource();

545

}

546

547

private void applyResource(QuarkusTestMethodContext context, Object resource) {

548

// Apply resource to test execution

549

}

550

}

551

```