or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bean-override-framework.mdindex.mdjdbc-testing.mdjunit-integration.mdmock-objects.mdtestcontext-framework.mdtesting-annotations.mdweb-testing.md

junit-integration.mddocs/

0

# JUnit Integration

1

2

Spring Test provides seamless integration with JUnit Jupiter (JUnit 5) through the SpringExtension and composite annotations. This integration enables Spring-specific features like dependency injection, transaction management, and context configuration in JUnit tests.

3

4

## Capabilities

5

6

### Spring Extension

7

8

The core JUnit Jupiter extension that integrates Spring TestContext Framework with JUnit 5.

9

10

```java { .api }

11

/**

12

* SpringExtension integrates the Spring TestContext Framework into JUnit 5's Jupiter programming model.

13

*

14

* To use this extension, simply annotate a JUnit Jupiter based test class with @ExtendWith(SpringExtension.class)

15

* or use composite annotations like @SpringJUnitConfig.

16

*/

17

public class SpringExtension implements BeforeAllCallback, AfterAllCallback,

18

TestInstancePostProcessor, BeforeEachCallback, AfterEachCallback,

19

BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver {

20

21

/**

22

* Delegates to TestContextManager.beforeTestClass().

23

* @param context the current extension context

24

*/

25

@Override

26

public void beforeAll(ExtensionContext context) throws Exception;

27

28

/**

29

* Delegates to TestContextManager.afterTestClass().

30

* @param context the current extension context

31

*/

32

@Override

33

public void afterAll(ExtensionContext context) throws Exception;

34

35

/**

36

* Delegates to TestContextManager.prepareTestInstance().

37

* @param testInstance the test instance to post-process

38

* @param context the current extension context

39

*/

40

@Override

41

public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception;

42

43

/**

44

* Delegates to TestContextManager.beforeTestMethod().

45

* @param context the current extension context

46

*/

47

@Override

48

public void beforeEach(ExtensionContext context) throws Exception;

49

50

/**

51

* Delegates to TestContextManager.beforeTestExecution().

52

* @param context the current extension context

53

*/

54

@Override

55

public void beforeTestExecution(ExtensionContext context) throws Exception;

56

57

/**

58

* Delegates to TestContextManager.afterTestExecution().

59

* @param context the current extension context

60

*/

61

@Override

62

public void afterTestExecution(ExtensionContext context) throws Exception;

63

64

/**

65

* Delegates to TestContextManager.afterTestMethod().

66

* @param context the current extension context

67

*/

68

@Override

69

public void afterEach(ExtensionContext context) throws Exception;

70

71

/**

72

* Resolve parameters from the Spring ApplicationContext if the parameter is of a supported type.

73

* @param parameterContext the context for the parameter for which an argument should be resolved

74

* @param extensionContext the extension context for the Executable about to be invoked

75

* @return true if this resolver can resolve an argument for the parameter

76

*/

77

@Override

78

public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext);

79

80

/**

81

* Resolve a parameter from the Spring ApplicationContext.

82

* @param parameterContext the context for the parameter for which an argument should be resolved

83

* @param extensionContext the extension context for the Executable about to be invoked

84

* @return the resolved argument for the parameter

85

* @throws ParameterResolutionException if the parameter cannot be resolved

86

*/

87

@Override

88

public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext);

89

}

90

```

91

92

### Composite Annotations

93

94

Convenient composed annotations that combine Spring testing features with JUnit Jupiter.

95

96

```java { .api }

97

/**

98

* @SpringJUnitConfig is a composed annotation that combines @ExtendWith(SpringExtension.class)

99

* from JUnit Jupiter with @ContextConfiguration from the Spring TestContext Framework.

100

*/

101

@ExtendWith(SpringExtension.class)

102

@ContextConfiguration

103

@Target(ElementType.TYPE)

104

@Retention(RetentionPolicy.RUNTIME)

105

@Documented

106

@Inherited

107

public @interface SpringJUnitConfig {

108

109

/**

110

* Alias for classes().

111

* @return an array of configuration classes

112

*/

113

@AliasFor(annotation = ContextConfiguration.class, attribute = "classes")

114

Class<?>[] value() default {};

115

116

/**

117

* The component classes to use for loading an ApplicationContext.

118

* @return an array of configuration classes

119

*/

120

@AliasFor(annotation = ContextConfiguration.class, attribute = "classes")

121

Class<?>[] classes() default {};

122

123

/**

124

* The resource locations to use for loading an ApplicationContext.

125

* @return an array of resource locations

126

*/

127

@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")

128

String[] locations() default {};

129

130

/**

131

* The application context initializer classes to use for initializing a ConfigurableApplicationContext.

132

* @return an array of initializer classes

133

*/

134

@AliasFor(annotation = ContextConfiguration.class, attribute = "initializers")

135

Class<? extends ApplicationContextInitializer<?>>[] initializers() default {};

136

137

/**

138

* Whether or not resource locations or component classes from test superclasses should be inherited.

139

* @return true if locations should be inherited

140

*/

141

@AliasFor(annotation = ContextConfiguration.class, attribute = "inheritLocations")

142

boolean inheritLocations() default true;

143

144

/**

145

* Whether or not context initializers from test superclasses should be inherited.

146

* @return true if initializers should be inherited

147

*/

148

@AliasFor(annotation = ContextConfiguration.class, attribute = "inheritInitializers")

149

boolean inheritInitializers() default true;

150

151

/**

152

* The name of the context hierarchy level represented by this configuration.

153

* @return the context hierarchy level name

154

*/

155

@AliasFor(annotation = ContextConfiguration.class, attribute = "name")

156

String name() default "";

157

}

158

159

/**

160

* @SpringJUnitWebConfig is a composed annotation that combines @SpringJUnitConfig

161

* with @WebAppConfiguration from the Spring TestContext Framework.

162

*/

163

@SpringJUnitConfig

164

@WebAppConfiguration

165

@Target(ElementType.TYPE)

166

@Retention(RetentionPolicy.RUNTIME)

167

@Documented

168

@Inherited

169

public @interface SpringJUnitWebConfig {

170

171

/**

172

* Alias for classes().

173

* @return an array of configuration classes

174

*/

175

@AliasFor(annotation = SpringJUnitConfig.class, attribute = "classes")

176

Class<?>[] value() default {};

177

178

/**

179

* The component classes to use for loading an ApplicationContext.

180

* @return an array of configuration classes

181

*/

182

@AliasFor(annotation = SpringJUnitConfig.class, attribute = "classes")

183

Class<?>[] classes() default {};

184

185

/**

186

* The resource locations to use for loading an ApplicationContext.

187

* @return an array of resource locations

188

*/

189

@AliasFor(annotation = SpringJUnitConfig.class, attribute = "locations")

190

String[] locations() default {};

191

192

/**

193

* The application context initializer classes to use for initializing a ConfigurableApplicationContext.

194

* @return an array of initializer classes

195

*/

196

@AliasFor(annotation = SpringJUnitConfig.class, attribute = "initializers")

197

Class<? extends ApplicationContextInitializer<?>>[] initializers() default {};

198

199

/**

200

* Whether or not resource locations or component classes from test superclasses should be inherited.

201

* @return true if locations should be inherited

202

*/

203

@AliasFor(annotation = SpringJUnitConfig.class, attribute = "inheritLocations")

204

boolean inheritLocations() default true;

205

206

/**

207

* Whether or not context initializers from test superclasses should be inherited.

208

* @return true if initializers should be inherited

209

*/

210

@AliasFor(annotation = SpringJUnitConfig.class, attribute = "inheritInitializers")

211

boolean inheritInitializers() default true;

212

213

/**

214

* The name of the context hierarchy level represented by this configuration.

215

* @return the context hierarchy level name

216

*/

217

@AliasFor(annotation = SpringJUnitConfig.class, attribute = "name")

218

String name() default "";

219

220

/**

221

* The resource path to the root of the web application.

222

* @return the resource path for the web application

223

*/

224

@AliasFor(annotation = WebAppConfiguration.class, attribute = "value")

225

String resourcePath() default "src/main/webapp";

226

}

227

```

228

229

### Conditional Test Execution

230

231

JUnit Jupiter extensions for conditional test execution based on Spring profiles and SpEL expressions.

232

233

```java { .api }

234

/**

235

* @EnabledIf is used to signal that the annotated test class or test method is enabled

236

* and should be executed if the supplied SpEL expression evaluates to true.

237

*/

238

@Target({ElementType.TYPE, ElementType.METHOD})

239

@Retention(RetentionPolicy.RUNTIME)

240

@Documented

241

@ExtendWith(SpringJUnitCondition.class)

242

public @interface EnabledIf {

243

244

/**

245

* The SpEL expression to evaluate.

246

* @return the SpEL expression

247

*/

248

String expression();

249

250

/**

251

* The reason this test is enabled.

252

* @return the reason

253

*/

254

String reason() default "";

255

256

/**

257

* Whether the ApplicationContext should be eagerly loaded to evaluate the expression.

258

* @return true if the context should be loaded

259

*/

260

boolean loadContext() default false;

261

}

262

263

/**

264

* @DisabledIf is used to signal that the annotated test class or test method is disabled

265

* and should not be executed if the supplied SpEL expression evaluates to true.

266

*/

267

@Target({ElementType.TYPE, ElementType.METHOD})

268

@Retention(RetentionPolicy.RUNTIME)

269

@Documented

270

@ExtendWith(SpringJUnitCondition.class)

271

public @interface DisabledIf {

272

273

/**

274

* The SpEL expression to evaluate.

275

* @return the SpEL expression

276

*/

277

String expression();

278

279

/**

280

* The reason this test is disabled.

281

* @return the reason

282

*/

283

String reason() default "";

284

285

/**

286

* Whether the ApplicationContext should be eagerly loaded to evaluate the expression.

287

* @return true if the context should be loaded

288

*/

289

boolean loadContext() default false;

290

}

291

292

/**

293

* SpringJUnitCondition is a JUnit Jupiter ExecutionCondition that supports the @EnabledIf and @DisabledIf annotations.

294

*/

295

public class SpringJUnitCondition implements ExecutionCondition {

296

297

/**

298

* Evaluate the condition for the given extension context.

299

* @param context the current extension context

300

* @return the evaluation result

301

*/

302

@Override

303

public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context);

304

}

305

```

306

307

### Parameter Resolution

308

309

Support for dependency injection in test method parameters.

310

311

```java { .api }

312

/**

313

* ApplicationContextParameterResolver resolves method parameters of type ApplicationContext

314

* (or sub-types thereof) for JUnit Jupiter test methods.

315

*/

316

public class ApplicationContextParameterResolver implements ParameterResolver {

317

318

/**

319

* Determine if this resolver supports the given parameter.

320

* @param parameterContext the parameter context

321

* @param extensionContext the extension context

322

* @return true if the parameter is supported

323

*/

324

@Override

325

public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext);

326

327

/**

328

* Resolve the parameter from the ApplicationContext.

329

* @param parameterContext the parameter context

330

* @param extensionContext the extension context

331

* @return the resolved parameter value

332

*/

333

@Override

334

public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext);

335

}

336

```

337

338

**Usage Examples:**

339

340

```java

341

import org.springframework.test.context.junit.jupiter.*;

342

import org.junit.jupiter.api.*;

343

import org.springframework.beans.factory.annotation.Autowired;

344

345

// Basic Spring JUnit integration

346

@SpringJUnitConfig(AppConfig.class)

347

class UserServiceIntegrationTest {

348

349

@Autowired

350

private UserService userService;

351

352

@Test

353

void shouldInjectDependencies() {

354

assertThat(userService).isNotNull();

355

356

User user = new User("John", "john@example.com");

357

User saved = userService.save(user);

358

assertThat(saved.getId()).isNotNull();

359

}

360

361

@Test

362

void shouldSupportParameterInjection(UserRepository userRepository) {

363

// Parameters can be injected from ApplicationContext

364

assertThat(userRepository).isNotNull();

365

366

long count = userRepository.count();

367

assertThat(count).isGreaterThanOrEqualTo(0);

368

}

369

}

370

371

// Web application testing

372

@SpringJUnitWebConfig(WebConfig.class)

373

class WebControllerIntegrationTest {

374

375

@Autowired

376

private MockMvc mockMvc;

377

378

@Autowired

379

private WebApplicationContext webApplicationContext;

380

381

@Test

382

void shouldLoadWebApplicationContext() {

383

assertThat(webApplicationContext).isNotNull();

384

assertThat(webApplicationContext.getServletContext()).isNotNull();

385

}

386

387

@Test

388

void shouldPerformWebRequests() throws Exception {

389

mockMvc.perform(get("/users"))

390

.andExpect(status().isOk())

391

.andExpect(content().contentType(MediaType.APPLICATION_JSON));

392

}

393

}

394

395

// Multiple configuration sources

396

@SpringJUnitConfig(locations = {"classpath:app-config.xml", "classpath:test-config.xml"})

397

class XmlConfigIntegrationTest {

398

399

@Autowired

400

private DataSource dataSource;

401

402

@Test

403

void shouldLoadXmlConfiguration() {

404

assertThat(dataSource).isNotNull();

405

}

406

}

407

408

// Conditional test execution

409

@SpringJUnitConfig(ConditionalTestConfig.class)

410

class ConditionalExecutionTest {

411

412

@Test

413

@EnabledIf("#{environment.acceptsProfiles('integration')}")

414

void shouldRunOnlyInIntegrationProfile() {

415

// This test runs only when 'integration' profile is active

416

}

417

418

@Test

419

@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('linux')}")

420

void shouldRunOnlyOnLinux() {

421

// This test runs only on Linux systems

422

}

423

424

@Test

425

@DisabledIf("#{T(java.time.LocalTime).now().hour < 9}")

426

void shouldNotRunBeforeNineAM() {

427

// This test is disabled before 9 AM

428

}

429

430

@Test

431

@EnabledIf(expression = "#{@testDataService.hasTestData()}", loadContext = true)

432

void shouldRunWhenTestDataExists() {

433

// This test runs only when test data exists (requires context loading)

434

}

435

}

436

437

// Nested test classes with Spring

438

@SpringJUnitConfig(NestedTestConfig.class)

439

class NestedSpringTests {

440

441

@Autowired

442

private UserService userService;

443

444

@Test

445

void shouldHaveUserService() {

446

assertThat(userService).isNotNull();

447

}

448

449

@Nested

450

@TestPropertySource(properties = "feature.enabled=true")

451

class WhenFeatureEnabled {

452

453

@Autowired

454

private FeatureService featureService;

455

456

@Test

457

void shouldEnableFeature() {

458

assertThat(featureService.isEnabled()).isTrue();

459

}

460

461

@Test

462

@EnabledIf("#{@featureService.isEnabled()}")

463

void shouldRunWhenFeatureIsEnabled() {

464

// Test feature-specific behavior

465

}

466

}

467

468

@Nested

469

@ActiveProfiles("mock")

470

class WithMockProfile {

471

472

@Test

473

void shouldUseMockBeans() {

474

// Tests with mock profile active

475

}

476

}

477

}

478

479

// Parameterized tests with Spring

480

@SpringJUnitConfig(ValidationTestConfig.class)

481

class ParameterizedSpringTest {

482

483

@Autowired

484

private ValidationService validationService;

485

486

@ParameterizedTest

487

@ValueSource(strings = {"john@example.com", "jane@test.org", "bob@company.net"})

488

void shouldValidateEmails(String email) {

489

ValidationResult result = validationService.validateEmail(email);

490

assertThat(result.isValid()).isTrue();

491

}

492

493

@ParameterizedTest

494

@CsvSource({

495

"John, john@example.com, true",

496

"'', invalid-email, false",

497

"Jane, jane@test.org, true"

498

})

499

void shouldValidateUsers(String name, String email, boolean expectedValid) {

500

User user = new User(name, email);

501

ValidationResult result = validationService.validateUser(user);

502

assertThat(result.isValid()).isEqualTo(expectedValid);

503

}

504

}

505

506

// Dynamic tests with Spring context

507

@SpringJUnitConfig(DynamicTestConfig.class)

508

class DynamicSpringTests {

509

510

@Autowired

511

private TestDataService testDataService;

512

513

@TestFactory

514

Stream<DynamicTest> shouldTestAllUsers() {

515

return testDataService.getAllTestUsers().stream()

516

.map(user -> DynamicTest.dynamicTest(

517

"Testing user: " + user.getName(),

518

() -> {

519

assertThat(user.getId()).isNotNull();

520

assertThat(user.getName()).isNotBlank();

521

assertThat(user.getEmail()).contains("@");

522

}

523

));

524

}

525

526

@TestFactory

527

Collection<DynamicTest> shouldValidateAllConfigurations(ConfigurationService configService) {

528

return configService.getAllConfigurations().stream()

529

.map(config -> DynamicTest.dynamicTest(

530

"Validating config: " + config.getName(),

531

() -> assertThat(configService.isValid(config)).isTrue()

532

))

533

.toList();

534

}

535

}

536

537

// Test lifecycle callbacks

538

@SpringJUnitConfig(LifecycleTestConfig.class)

539

class TestLifecycleExample {

540

541

@Autowired

542

private DatabaseService databaseService;

543

544

@BeforeAll

545

static void setupClass() {

546

// Class-level setup

547

System.setProperty("test.environment", "junit5");

548

}

549

550

@BeforeEach

551

void setUp() {

552

// Method-level setup - Spring context is available here

553

databaseService.clearCache();

554

}

555

556

@Test

557

void shouldHaveCleanState() {

558

assertThat(databaseService.getCacheSize()).isZero();

559

}

560

561

@AfterEach

562

void tearDown() {

563

// Method-level cleanup

564

databaseService.resetToDefaults();

565

}

566

567

@AfterAll

568

static void tearDownClass() {

569

// Class-level cleanup

570

System.clearProperty("test.environment");

571

}

572

}

573

```

574

575

## Types

576

577

```java { .api }

578

/**

579

* Encapsulates the context in which a test is executed, agnostic of the actual testing framework in use.

580

* Used by SpringExtension to bridge JUnit Jupiter and Spring TestContext Framework.

581

*/

582

public interface TestContext {

583

584

/**

585

* Get the application context for this test context.

586

* @return the application context (never null)

587

* @throws IllegalStateException if an error occurs while retrieving the application context

588

*/

589

ApplicationContext getApplicationContext();

590

591

/**

592

* Get the test class for this test context.

593

* @return the test class (never null)

594

*/

595

Class<?> getTestClass();

596

597

/**

598

* Get the current test instance for this test context.

599

* @return the current test instance (may be null)

600

*/

601

@Nullable

602

Object getTestInstance();

603

604

/**

605

* Get the current test method for this test context.

606

* @return the current test method (may be null)

607

*/

608

@Nullable

609

Method getTestMethod();

610

}

611

612

/**

613

* Strategy interface for resolving test method parameters from a Spring ApplicationContext.

614

*/

615

public interface TestContextParameterResolver {

616

617

/**

618

* Determine if this resolver can resolve the given parameter.

619

* @param parameter the parameter to resolve

620

* @param testClass the test class

621

* @param applicationContext the Spring application context

622

* @return true if the parameter can be resolved

623

*/

624

boolean supportsParameter(Parameter parameter, Class<?> testClass, ApplicationContext applicationContext);

625

626

/**

627

* Resolve the given parameter from the application context.

628

* @param parameter the parameter to resolve

629

* @param testClass the test class

630

* @param applicationContext the Spring application context

631

* @return the resolved parameter value

632

*/

633

Object resolveParameter(Parameter parameter, Class<?> testClass, ApplicationContext applicationContext);

634

}

635

636

/**

637

* Exception thrown when parameter resolution fails in Spring test context.

638

*/

639

public class ParameterResolutionException extends RuntimeException {

640

641

/**

642

* Create a new ParameterResolutionException.

643

* @param message the detail message

644

*/

645

public ParameterResolutionException(String message);

646

647

/**

648

* Create a new ParameterResolutionException.

649

* @param message the detail message

650

* @param cause the root cause

651

*/

652

public ParameterResolutionException(String message, @Nullable Throwable cause);

653

}

654

```