0
# Testing Annotations
1
2
Spring Test provides a comprehensive set of annotations for configuring test behavior, context loading, and transaction management. These annotations enable declarative configuration of test scenarios and integration with the Spring TestContext Framework.
3
4
## Capabilities
5
6
### Context Configuration Annotations
7
8
Annotations for configuring the ApplicationContext in Spring tests.
9
10
```java { .api }
11
/**
12
* @TestPropertySource configures the locations of properties files and inlined properties
13
* to be added to the Environment's set of PropertySources for an ApplicationContext.
14
*/
15
@Target(ElementType.TYPE)
16
@Retention(RetentionPolicy.RUNTIME)
17
@Documented
18
@Inherited
19
public @interface TestPropertySource {
20
21
/**
22
* Alias for locations().
23
* @return an array of resource locations for properties files
24
*/
25
@AliasFor("locations")
26
String[] value() default {};
27
28
/**
29
* The resource locations of properties files to be loaded into the Environment's PropertySources.
30
* @return an array of resource locations
31
*/
32
@AliasFor("value")
33
String[] locations() default {};
34
35
/**
36
* Inlined properties in the form of key=value pairs to be added to the Environment's PropertySources.
37
* @return an array of inlined properties
38
*/
39
String[] properties() default {};
40
41
/**
42
* Whether or not test property source locations should be inherited from superclasses.
43
* @return true if locations should be inherited
44
*/
45
boolean inheritLocations() default true;
46
47
/**
48
* Whether or not inlined test properties should be inherited from superclasses.
49
* @return true if properties should be inherited
50
*/
51
boolean inheritProperties() default true;
52
53
/**
54
* The application context resource loading factory class to use.
55
* @return the factory class
56
*/
57
Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
58
}
59
60
/**
61
* @DynamicPropertySource is a method-level annotation that can be used to register
62
* dynamic properties to be added to the Environment's set of PropertySources.
63
*/
64
@Target(ElementType.METHOD)
65
@Retention(RetentionPolicy.RUNTIME)
66
@Documented
67
public @interface DynamicPropertySource {
68
69
/**
70
* The name of the dynamic property source.
71
* @return the property source name
72
*/
73
String value() default "";
74
}
75
76
/**
77
* @WebAppConfiguration is a class-level annotation that is used to declare that
78
* the ApplicationContext loaded for an integration test should be a WebApplicationContext.
79
*/
80
@Target(ElementType.TYPE)
81
@Retention(RetentionPolicy.RUNTIME)
82
@Documented
83
@Inherited
84
public @interface WebAppConfiguration {
85
86
/**
87
* The resource path to the root of the web application.
88
* @return the resource path
89
*/
90
String value() default "src/main/webapp";
91
}
92
93
/**
94
* @BootstrapWith is a class-level annotation that is used to configure how the
95
* Spring TestContext Framework is bootstrapped.
96
*/
97
@Target(ElementType.TYPE)
98
@Retention(RetentionPolicy.RUNTIME)
99
@Documented
100
@Inherited
101
public @interface BootstrapWith {
102
103
/**
104
* The TestContextBootstrapper to use to bootstrap the TestContext Framework.
105
* @return the TestContextBootstrapper class
106
*/
107
Class<? extends TestContextBootstrapper> value() default TestContextBootstrapper.class;
108
}
109
```
110
111
### Test Execution Annotations
112
113
Annotations for controlling test execution behavior and lifecycle.
114
115
```java { .api }
116
/**
117
* @DirtiesContext indicates that the underlying Spring ApplicationContext has been
118
* dirtied during the execution of a test and should be closed and removed from the context cache.
119
*/
120
@Target({ElementType.TYPE, ElementType.METHOD})
121
@Retention(RetentionPolicy.RUNTIME)
122
@Documented
123
@Inherited
124
public @interface DirtiesContext {
125
126
/**
127
* The mode to use when a test method is annotated with @DirtiesContext.
128
* @return the method mode
129
*/
130
MethodMode methodMode() default MethodMode.AFTER_METHOD;
131
132
/**
133
* The mode to use when a test class is annotated with @DirtiesContext.
134
* @return the class mode
135
*/
136
ClassMode classMode() default ClassMode.AFTER_CLASS;
137
138
/**
139
* The context hierarchy mode to use when @DirtiesContext is present on a test class.
140
* @return the hierarchy mode
141
*/
142
HierarchyMode hierarchyMode() default HierarchyMode.EXHAUSTIVE;
143
144
/**
145
* Defines modes which determine when a test class's ApplicationContext should be marked as dirty.
146
*/
147
enum ClassMode {
148
149
/**
150
* The associated ApplicationContext will be marked as dirty before the test class.
151
*/
152
BEFORE_CLASS,
153
154
/**
155
* The associated ApplicationContext will be marked as dirty before each test method in the class.
156
*/
157
BEFORE_EACH_TEST_METHOD,
158
159
/**
160
* The associated ApplicationContext will be marked as dirty after each test method in the class.
161
*/
162
AFTER_EACH_TEST_METHOD,
163
164
/**
165
* The associated ApplicationContext will be marked as dirty after the test class.
166
*/
167
AFTER_CLASS
168
}
169
170
/**
171
* Defines modes which determine when a test method's ApplicationContext should be marked as dirty.
172
*/
173
enum MethodMode {
174
175
/**
176
* The associated ApplicationContext will be marked as dirty before the test method.
177
*/
178
BEFORE_METHOD,
179
180
/**
181
* The associated ApplicationContext will be marked as dirty after the test method.
182
*/
183
AFTER_METHOD
184
}
185
186
/**
187
* Defines modes which determine how @DirtiesContext is interpreted when used in a test class hierarchy.
188
*/
189
enum HierarchyMode {
190
191
/**
192
* The ApplicationContext will be removed from the context cache along with all other
193
* contexts in the same hierarchy.
194
*/
195
EXHAUSTIVE,
196
197
/**
198
* Only the ApplicationContext of the current level in the context hierarchy will be removed from the context cache.
199
*/
200
CURRENT_LEVEL
201
}
202
}
203
204
/**
205
* @TestExecutionListeners defines class-level metadata for configuring which
206
* TestExecutionListeners should be registered with the TestContextManager.
207
*/
208
@Target(ElementType.TYPE)
209
@Retention(RetentionPolicy.RUNTIME)
210
@Documented
211
@Inherited
212
public @interface TestExecutionListeners {
213
214
/**
215
* The TestExecutionListeners to register with the TestContextManager.
216
* @return an array of TestExecutionListener classes
217
*/
218
Class<? extends TestExecutionListener>[] value() default {};
219
220
/**
221
* Alias for value().
222
* @return an array of TestExecutionListener classes
223
*/
224
@AliasFor("value")
225
Class<? extends TestExecutionListener>[] listeners() default {};
226
227
/**
228
* Whether or not TestExecutionListeners from superclasses should be inherited.
229
* @return true if listeners should be inherited
230
*/
231
boolean inheritListeners() default true;
232
233
/**
234
* The merge mode to use when @TestExecutionListeners is declared on a class
235
* that does not inherit listeners from a superclass.
236
* @return the merge mode
237
*/
238
MergeMode mergeMode() default MergeMode.REPLACE_DEFAULTS;
239
240
/**
241
* Enumeration of modes that dictate whether explicitly declared listeners are
242
* merged with the default listeners when @TestExecutionListeners is declared on a class.
243
*/
244
enum MergeMode {
245
246
/**
247
* Locally declared listeners should be merged with the default listeners.
248
*/
249
MERGE_WITH_DEFAULTS,
250
251
/**
252
* Locally declared listeners should replace the default listeners.
253
*/
254
REPLACE_DEFAULTS
255
}
256
}
257
258
/**
259
* @RecordApplicationEvents is a class-level annotation that is used to instruct the
260
* Spring TestContext Framework to record all application events that are published
261
* in the ApplicationContext during the execution of a single test.
262
*/
263
@Target(ElementType.TYPE)
264
@Retention(RetentionPolicy.RUNTIME)
265
@Documented
266
@Inherited
267
public @interface RecordApplicationEvents {
268
}
269
```
270
271
### Transaction Annotations
272
273
Annotations for controlling transactional behavior in tests.
274
275
```java { .api }
276
/**
277
* @Transactional can be used to configure transactional test methods to run within a transaction.
278
* When used at the class level, it establishes default transaction semantics for all test methods.
279
*/
280
@Target({ElementType.TYPE, ElementType.METHOD})
281
@Retention(RetentionPolicy.RUNTIME)
282
@Documented
283
@Inherited
284
public @interface Transactional {
285
286
/**
287
* Alias for transactionManager().
288
* @return the transaction manager bean name
289
*/
290
@AliasFor("transactionManager")
291
String value() default "";
292
293
/**
294
* The bean name of the PlatformTransactionManager that should be used to drive transactions.
295
* @return the transaction manager bean name
296
*/
297
@AliasFor("value")
298
String transactionManager() default "";
299
300
/**
301
* The transaction propagation type.
302
* @return the propagation type
303
*/
304
Propagation propagation() default Propagation.REQUIRED;
305
306
/**
307
* The transaction isolation level.
308
* @return the isolation level
309
*/
310
Isolation isolation() default Isolation.DEFAULT;
311
312
/**
313
* The timeout for this transaction (in seconds).
314
* @return the timeout value
315
*/
316
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
317
318
/**
319
* The timeout for this transaction (in seconds).
320
* @return the timeout value as a String
321
*/
322
String timeoutString() default "";
323
324
/**
325
* A boolean flag that can be set to true if the transaction is effectively read-only.
326
* @return true if the transaction is read-only
327
*/
328
boolean readOnly() default false;
329
330
/**
331
* Defines zero or more exception classes, which must be subclasses of Throwable,
332
* indicating which exception types must cause a transaction rollback.
333
* @return an array of exception classes
334
*/
335
Class<? extends Throwable>[] rollbackFor() default {};
336
337
/**
338
* Defines zero or more exception class names (for exceptions which must be subclasses of Throwable)
339
* indicating which exception types must cause a transaction rollback.
340
* @return an array of exception class names
341
*/
342
String[] rollbackForClassName() default {};
343
344
/**
345
* Defines zero or more exception classes, which must be subclasses of Throwable,
346
* indicating which exception types must not cause a transaction rollback.
347
* @return an array of exception classes
348
*/
349
Class<? extends Throwable>[] noRollbackFor() default {};
350
351
/**
352
* Defines zero or more exception class names (for exceptions which must be subclasses of Throwable)
353
* indicating which exception types must not cause a transaction rollback.
354
* @return an array of exception class names
355
*/
356
String[] noRollbackForClassName() default {};
357
}
358
359
/**
360
* @Rollback indicates whether the transaction for a transactional test method should be rolled back
361
* after the test method has completed.
362
*/
363
@Target({ElementType.TYPE, ElementType.METHOD})
364
@Retention(RetentionPolicy.RUNTIME)
365
@Documented
366
@Inherited
367
public @interface Rollback {
368
369
/**
370
* Whether the transaction should be rolled back after the test has completed.
371
* @return true if the transaction should be rolled back
372
*/
373
boolean value() default true;
374
}
375
376
/**
377
* @Commit indicates that the transaction for a transactional test method should be committed
378
* after the test method has completed.
379
*/
380
@Target({ElementType.TYPE, ElementType.METHOD})
381
@Retention(RetentionPolicy.RUNTIME)
382
@Documented
383
@Inherited
384
public @interface Commit {
385
}
386
```
387
388
### Test Method Annotations
389
390
Annotations for individual test method configuration and execution control.
391
392
```java { .api }
393
/**
394
* @Repeat indicates that the annotated test method should be executed repeatedly.
395
*/
396
@Target(ElementType.METHOD)
397
@Retention(RetentionPolicy.RUNTIME)
398
@Documented
399
public @interface Repeat {
400
401
/**
402
* The number of times that the annotated test method should be repeated.
403
* @return the repeat count
404
*/
405
int value() default 1;
406
}
407
408
/**
409
* @Timed indicates that the annotated test method must finish execution in a specified time period.
410
*/
411
@Target(ElementType.METHOD)
412
@Retention(RetentionPolicy.RUNTIME)
413
@Documented
414
public @interface Timed {
415
416
/**
417
* The maximum amount of time (in milliseconds) that the test execution can take
418
* without being marked as failed due to taking too long.
419
* @return the timeout in milliseconds
420
*/
421
long millis() default 0L;
422
}
423
424
/**
425
* @IfProfileValue indicates that the annotated test is enabled for a specific testing environment.
426
*/
427
@Target({ElementType.TYPE, ElementType.METHOD})
428
@Retention(RetentionPolicy.RUNTIME)
429
@Documented
430
@Inherited
431
public @interface IfProfileValue {
432
433
/**
434
* The name of the profile value against which to test.
435
* @return the profile value name
436
*/
437
String name() default "";
438
439
/**
440
* The expected value of the named profile value.
441
* @return the expected value
442
*/
443
String value() default "";
444
445
/**
446
* A list of all expected values for the named profile value.
447
* @return an array of expected values
448
*/
449
String[] values() default {};
450
}
451
452
/**
453
* @ProfileValueSourceConfiguration is a class-level annotation that is used to specify
454
* what type of ProfileValueSource to use when retrieving profile values configured via @IfProfileValue.
455
*/
456
@Target(ElementType.TYPE)
457
@Retention(RetentionPolicy.RUNTIME)
458
@Documented
459
@Inherited
460
public @interface ProfileValueSourceConfiguration {
461
462
/**
463
* The type of ProfileValueSource to use when retrieving profile values.
464
* @return the ProfileValueSource class
465
*/
466
Class<? extends ProfileValueSource> value() default SystemProfileValueSource.class;
467
}
468
```
469
470
**Usage Examples:**
471
472
```java
473
import org.springframework.test.annotation.*;
474
import org.springframework.test.context.*;
475
import org.springframework.transaction.annotation.Transactional;
476
477
// Basic test configuration
478
@SpringJUnitConfig(TestConfig.class)
479
@TestPropertySource(locations = "/test.properties",
480
properties = {"app.name=TestApp", "debug=true"})
481
@ActiveProfiles("test")
482
class UserServiceTest {
483
484
@Autowired
485
private UserService userService;
486
487
@Test
488
@Transactional
489
@Rollback
490
void shouldCreateUserInTransaction() {
491
User user = new User("John", "john@example.com");
492
User saved = userService.save(user);
493
assertThat(saved.getId()).isNotNull();
494
// Transaction will be rolled back
495
}
496
497
@Test
498
@Transactional
499
@Commit
500
void shouldCommitUserCreation() {
501
User user = new User("Jane", "jane@example.com");
502
userService.save(user);
503
// Transaction will be committed
504
}
505
}
506
507
// Dynamic property configuration
508
@SpringJUnitConfig(DatabaseTestConfig.class)
509
class DatabaseIntegrationTest {
510
511
@DynamicPropertySource
512
static void configureDatabaseProperties(DynamicPropertyRegistry registry) {
513
registry.add("spring.datasource.url", () -> database.getJdbcUrl());
514
registry.add("spring.datasource.username", database::getUsername);
515
registry.add("spring.datasource.password", database::getPassword);
516
}
517
518
@Test
519
void shouldConnectToDatabase() {
520
// Test with dynamic database configuration
521
}
522
}
523
524
// Context dirtying scenarios
525
@SpringJUnitConfig(CacheTestConfig.class)
526
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
527
class CacheIntegrationTest {
528
529
@Autowired
530
private CacheManager cacheManager;
531
532
@Test
533
void shouldCacheData() {
534
// Test caching behavior
535
// Context will be marked dirty after this method
536
}
537
538
@Test
539
@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
540
void shouldStartWithCleanCache() {
541
// Context will be marked dirty before this method
542
// Test with fresh cache
543
}
544
}
545
546
// Web application configuration
547
@SpringJUnitWebConfig(WebConfig.class)
548
@WebAppConfiguration("src/test/webapp")
549
class WebControllerTest {
550
551
@Autowired
552
private WebApplicationContext webContext;
553
554
@Autowired
555
private MockMvc mockMvc;
556
557
@Test
558
void shouldLoadWebContext() {
559
assertThat(webContext).isNotNull();
560
assertThat(webContext.getServletContext()).isNotNull();
561
}
562
}
563
564
// Profile-based conditional execution
565
@SpringJUnitConfig(ProfileTestConfig.class)
566
@ProfileValueSourceConfiguration(SystemProfileValueSource.class)
567
class ConditionalTest {
568
569
@Test
570
@IfProfileValue(name = "test.environment", value = "integration")
571
void shouldRunOnlyInIntegrationEnvironment() {
572
// This test runs only when system property test.environment=integration
573
}
574
575
@Test
576
@IfProfileValue(name = "os.name", values = {"Linux", "Mac OS X"})
577
void shouldRunOnUnixSystems() {
578
// This test runs only on specified operating systems
579
}
580
}
581
582
// Repeated execution and timing
583
@SpringJUnitConfig(PerformanceTestConfig.class)
584
class PerformanceTest {
585
586
@Test
587
@Repeat(5)
588
@Timed(millis = 1000)
589
void shouldCompleteWithin1Second() {
590
// This test will be repeated 5 times and must complete within 1 second each time
591
performanceService.executeOperation();
592
}
593
}
594
595
// Event recording
596
@SpringJUnitConfig(EventTestConfig.class)
597
@RecordApplicationEvents
598
class EventPublishingTest {
599
600
@Autowired
601
private ApplicationEventPublisher eventPublisher;
602
603
@Autowired
604
private ApplicationEvents events;
605
606
@Test
607
void shouldRecordPublishedEvents() {
608
eventPublisher.publishEvent(new UserCreatedEvent("John"));
609
eventPublisher.publishEvent(new UserUpdatedEvent("John"));
610
611
assertThat(events.stream(UserCreatedEvent.class)).hasSize(1);
612
assertThat(events.stream(UserUpdatedEvent.class)).hasSize(1);
613
assertThat(events.stream().count()).isEqualTo(2);
614
}
615
}
616
617
// Custom test execution listeners
618
@SpringJUnitConfig(CustomTestConfig.class)
619
@TestExecutionListeners(
620
listeners = {CustomTestExecutionListener.class, MetricsCollectionListener.class},
621
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
622
)
623
class CustomExecutionTest {
624
625
@Test
626
void shouldUseCustomListeners() {
627
// Test will execute with custom listeners in addition to default ones
628
}
629
}
630
```
631
632
## Types
633
634
```java { .api }
635
/**
636
* Strategy interface for providing profile values programmatically.
637
*/
638
public interface ProfileValueSource {
639
640
/**
641
* Get the profile value indicated by the specified key.
642
* @param key the name of the profile value
643
* @return the String value of the profile value, or null if there is no value with that key
644
*/
645
@Nullable
646
String get(String key);
647
}
648
649
/**
650
* Default implementation of ProfileValueSource which resolves system properties
651
* and system environment variables.
652
*/
653
public class SystemProfileValueSource implements ProfileValueSource {
654
655
/**
656
* Get the profile value for the given key from system properties,
657
* falling back to environment variables if not found.
658
* @param key the profile value key
659
* @return the profile value, or null if not found
660
*/
661
@Nullable
662
@Override
663
public String get(String key);
664
}
665
666
/**
667
* Registry for dynamic properties to be added to the Environment during test execution.
668
*/
669
public interface DynamicPropertyRegistry {
670
671
/**
672
* Add a dynamic property with the given name and Supplier of the value.
673
* @param name the property name
674
* @param valueSupplier a supplier for the property value
675
*/
676
void add(String name, Supplier<Object> valueSupplier);
677
678
/**
679
* Add a dynamic property with the given name and value.
680
* @param name the property name
681
* @param value the property value
682
*/
683
void add(String name, Object value);
684
}
685
686
/**
687
* ApplicationEvents encapsulates all ApplicationEvents that were published
688
* during the execution of a single test and provides methods to interact with those events.
689
*/
690
public interface ApplicationEvents {
691
692
/**
693
* Get a stream of all application events of the specified type that were published during test execution.
694
* @param type the event type
695
* @param <T> the event type
696
* @return a stream of events of the specified type
697
*/
698
<T extends ApplicationEvent> Stream<T> stream(Class<T> type);
699
700
/**
701
* Get a stream of all application events that were published during test execution.
702
* @return a stream of all events
703
*/
704
Stream<ApplicationEvent> stream();
705
706
/**
707
* Clear all recorded events.
708
*/
709
void clear();
710
}
711
712
### Additional Testing Annotations
713
714
Key annotations for advanced test configuration and execution control.
715
716
```java { .api }
717
/**
718
* @RecordApplicationEvents indicates that ApplicationEvents published in the ApplicationContext
719
* should be recorded and made available to the test via ApplicationEvents.
720
*/
721
@Target(ElementType.TYPE)
722
@Retention(RetentionPolicy.RUNTIME)
723
@Documented
724
@Inherited
725
public @interface RecordApplicationEvents {
726
}
727
728
/**
729
* @DisabledInAotMode indicates that the annotated test class or test method should be disabled
730
* when running in AOT (ahead-of-time) processing mode.
731
*/
732
@Target({ElementType.TYPE, ElementType.METHOD})
733
@Retention(RetentionPolicy.RUNTIME)
734
@Documented
735
public @interface DisabledInAotMode {
736
737
/**
738
* The reason this test is disabled in AOT mode.
739
* @return the reason for disabling in AOT mode
740
*/
741
String value() default "";
742
}
743
744
/**
745
* @NestedTestConfiguration indicates how test configuration should be handled for @Nested test classes.
746
*/
747
@Target(ElementType.TYPE)
748
@Retention(RetentionPolicy.RUNTIME)
749
@Documented
750
@Inherited
751
public @interface NestedTestConfiguration {
752
753
/**
754
* The nested test configuration mode.
755
* @return the configuration mode
756
*/
757
EnclosingConfiguration value();
758
759
/**
760
* Enum defining nested test configuration behavior.
761
*/
762
enum EnclosingConfiguration {
763
/**
764
* Inherit configuration from the enclosing test class.
765
*/
766
INHERIT,
767
768
/**
769
* Override configuration from the enclosing test class.
770
*/
771
OVERRIDE
772
}
773
}
774
775
/**
776
* @DynamicPropertySource can be used to register dynamic properties to be added to
777
* the Environment's set of PropertySources for an ApplicationContext loaded for an integration test.
778
*/
779
@Target(ElementType.METHOD)
780
@Retention(RetentionPolicy.RUNTIME)
781
@Documented
782
public @interface DynamicPropertySource {
783
784
/**
785
* The name that can be used to reference this dynamic property source.
786
* @return the name for this property source
787
*/
788
String value() default "";
789
}
790
```
791
792
### Types
793
794
```java { .api }
795
/**
796
* Functional interface for dynamic property registration.
797
*/
798
@FunctionalInterface
799
public interface DynamicPropertyRegistry {
800
801
/**
802
* Add a Supplier for the given property name to this registry.
803
* @param name the property name
804
* @param valueSupplier the supplier for the property value
805
*/
806
void add(String name, Supplier<Object> valueSupplier);
807
}
808
```
809
810
/**
811
* Utility class for working with test annotations.
812
*/
813
public abstract class TestAnnotationUtils {
814
815
/**
816
* Get the repeat count for the specified test method.
817
* @param testMethod the test method
818
* @return the repeat count, or 1 if no @Repeat annotation is present
819
*/
820
public static int getRepeatCount(Method testMethod);
821
822
/**
823
* Get the timeout for the specified test method.
824
* @param testMethod the test method
825
* @return the timeout in milliseconds, or 0 if no @Timed annotation is present
826
*/
827
public static long getTimeout(Method testMethod);
828
829
/**
830
* Determine if the supplied test method is annotated with @Timed.
831
* @param testMethod the test method to check
832
* @return true if the method is annotated with @Timed
833
*/
834
public static boolean isTimed(Method testMethod);
835
836
/**
837
* Determine if the supplied test method is annotated with @Repeat.
838
* @param testMethod the test method to check
839
* @return true if the method is annotated with @Repeat
840
*/
841
public static boolean isRepeated(Method testMethod);
842
}
843
```