Skip to content

Commit 98d0ca9

Browse files
committed
Allow @ExtendWith to be declared directly on fields and parameters
Prior to this commit, @ExtendWith could only be declared on types (i.e., classes, interfaces, annotations) and methods. @ExtendWith can now be declared directly on fields and parameters as well. See #864, #2680
1 parent ee18ea7 commit 98d0ca9

File tree

2 files changed

+70
-27
lines changed

2 files changed

+70
-27
lines changed

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtendWith.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@
2424

2525
/**
2626
* {@code @ExtendWith} is a {@linkplain Repeatable repeatable} annotation
27-
* that is used to register {@linkplain Extension extensions} for the
28-
* annotated test class or test method.
27+
* that is used to register {@linkplain Extension extensions} for the annotated
28+
* test class, test interface, test method, field, or parameter.
29+
*
30+
* <p>Annotated parameters are supported in test class constructors, in test
31+
* methods, and in {@code @BeforeAll}, {@code @AfterAll}, {@code @BeforeEach},
32+
* and {@code @AfterEach} lifecycle methods.
2933
*
3034
* <h3>Supported Extension APIs</h3>
3135
* <ul>
@@ -49,7 +53,7 @@
4953
* @see RegisterExtension
5054
* @see Extension
5155
*/
52-
@Target({ ElementType.TYPE, ElementType.METHOD })
56+
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
5357
@Retention(RetentionPolicy.RUNTIME)
5458
@Documented
5559
@Inherited

junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ void registrationOrder(LogRecordListener listener) {
139139
assertOneTestSucceeded(AllInOneWithTestInstancePerMethodTestCase.class);
140140
assertThat(getRegisteredLocalExtensions(listener))//
141141
.containsExactly(//
142-
"StaticField", // @ExtendWith on static field
142+
"StaticField1", // @ExtendWith on static field
143+
"StaticField2", // @ExtendWith on static field
143144
"ClassLevelExtension1", // @RegisterExtension on static field
144145
"ClassLevelExtension2", // @RegisterExtension on static field
145146
"ConstructorParameter", // @ExtendWith on parameter in constructor
@@ -148,7 +149,8 @@ void registrationOrder(LogRecordListener listener) {
148149
"AfterEachParameter", // @ExtendWith on parameter in @AfterEach method
149150
"AfterAllParameter", // @ExtendWith on parameter in static @AfterAll method
150151
"TestParameter", // @ExtendWith on parameter in @Test method
151-
"InstanceField", // @ExtendWith on instance field
152+
"InstanceField1", // @ExtendWith on instance field
153+
"InstanceField2", // @ExtendWith on instance field
152154
"InstanceLevelExtension1", // @RegisterExtension on instance field
153155
"InstanceLevelExtension2"// @RegisterExtension on instance field
154156
);
@@ -157,15 +159,17 @@ void registrationOrder(LogRecordListener listener) {
157159
assertOneTestSucceeded(AllInOneWithTestInstancePerClassTestCase.class);
158160
assertThat(getRegisteredLocalExtensions(listener))//
159161
.containsExactly(//
160-
"StaticField", // @ExtendWith on static field
162+
"StaticField1", // @ExtendWith on static field
163+
"StaticField2", // @ExtendWith on static field
161164
"ClassLevelExtension1", // @RegisterExtension on static field
162165
"ClassLevelExtension2", // @RegisterExtension on static field
163166
"ConstructorParameter", // @ExtendWith on parameter in constructor
164167
"BeforeAllParameter", // @ExtendWith on parameter in static @BeforeAll method
165168
"BeforeEachParameter", // @ExtendWith on parameter in @BeforeEach method
166169
"AfterEachParameter", // @ExtendWith on parameter in @AfterEach method
167170
"AfterAllParameter", // @ExtendWith on parameter in static @AfterAll method
168-
"InstanceField", // @ExtendWith on instance field
171+
"InstanceField1", // @ExtendWith on instance field
172+
"InstanceField2", // @ExtendWith on instance field
169173
"InstanceLevelExtension1", // @RegisterExtension on instance field
170174
"InstanceLevelExtension2", // @RegisterExtension on instance field
171175
"TestParameter" // @ExtendWith on parameter in @Test method
@@ -598,11 +602,19 @@ void test() {
598602
@TestInstance(Lifecycle.PER_METHOD)
599603
static class AllInOneWithTestInstancePerMethodTestCase {
600604

601-
@StaticField
602-
static String staticField;
605+
@StaticField1
606+
static String staticField1;
603607

604-
@InstanceField
605-
String instanceField;
608+
@StaticField2
609+
@ExtendWith(StaticField2.Extension.class)
610+
static String staticField2;
611+
612+
@InstanceField1
613+
String instanceField1;
614+
615+
@InstanceField2
616+
@ExtendWith(InstanceField2.Extension.class)
617+
String instanceField2;
606618

607619
@RegisterExtension
608620
@Order(1)
@@ -625,36 +637,44 @@ static class AllInOneWithTestInstancePerMethodTestCase {
625637
}
626638

627639
@BeforeAll
628-
static void beforeAll(@BeforeAllParameter String text) {
640+
static void beforeAll(@ExtendWith(BeforeAllParameter.Extension.class) @BeforeAllParameter String text) {
629641
assertThat(text).isEqualTo("enigma");
630-
assertThat(staticField).isEqualTo("beforeAll - staticField");
642+
assertThat(staticField1).isEqualTo("beforeAll - staticField1");
643+
assertThat(staticField2).isEqualTo("beforeAll - staticField2");
631644
}
632645

633646
@BeforeEach
634647
void beforeEach(@BeforeEachParameter String text) {
635648
assertThat(text).isEqualTo("enigma");
636-
assertThat(staticField).isEqualTo("beforeAll - staticField");
637-
assertThat(instanceField).isEqualTo("beforeEach - instanceField");
649+
assertThat(staticField1).isEqualTo("beforeAll - staticField1");
650+
assertThat(staticField2).isEqualTo("beforeAll - staticField2");
651+
assertThat(instanceField1).isEqualTo("beforeEach - instanceField1");
652+
assertThat(instanceField2).isEqualTo("beforeEach - instanceField2");
638653
}
639654

640655
@Test
641656
void test(@TestParameter String text) {
642657
assertThat(text).isEqualTo("enigma");
643-
assertThat(staticField).isEqualTo("beforeAll - staticField");
644-
assertThat(instanceField).isEqualTo("beforeEach - instanceField");
658+
assertThat(staticField1).isEqualTo("beforeAll - staticField1");
659+
assertThat(staticField2).isEqualTo("beforeAll - staticField2");
660+
assertThat(instanceField1).isEqualTo("beforeEach - instanceField1");
661+
assertThat(instanceField2).isEqualTo("beforeEach - instanceField2");
645662
}
646663

647664
@AfterEach
648665
void afterEach(@AfterEachParameter String text) {
649666
assertThat(text).isEqualTo("enigma");
650-
assertThat(staticField).isEqualTo("beforeAll - staticField");
651-
assertThat(instanceField).isEqualTo("beforeEach - instanceField");
667+
assertThat(staticField1).isEqualTo("beforeAll - staticField1");
668+
assertThat(staticField2).isEqualTo("beforeAll - staticField2");
669+
assertThat(instanceField1).isEqualTo("beforeEach - instanceField1");
670+
assertThat(instanceField2).isEqualTo("beforeEach - instanceField2");
652671
}
653672

654673
@AfterAll
655674
static void afterAll(@AfterAllParameter String text) {
656675
assertThat(text).isEqualTo("enigma");
657-
assertThat(staticField).isEqualTo("beforeAll - staticField");
676+
assertThat(staticField1).isEqualTo("beforeAll - staticField1");
677+
assertThat(staticField2).isEqualTo("beforeAll - staticField2");
658678
}
659679

660680
}
@@ -730,7 +750,8 @@ class Extension extends BaseParameterExtension<ConstructorParameter> {
730750

731751
@Target(ElementType.PARAMETER)
732752
@Retention(RetentionPolicy.RUNTIME)
733-
@ExtendWith(BeforeAllParameter.Extension.class)
753+
// Intentionally NOT annotated as follows
754+
// @ExtendWith(BeforeAllParameter.Extension.class)
734755
@interface BeforeAllParameter {
735756
class Extension extends BaseParameterExtension<BeforeAllParameter> {
736757
}
@@ -811,17 +832,35 @@ class Extension extends BaseFieldExtension<MagicField> {
811832

812833
@Target(ElementType.FIELD)
813834
@Retention(RetentionPolicy.RUNTIME)
814-
@ExtendWith(InstanceField.Extension.class)
815-
@interface InstanceField {
816-
class Extension extends BaseFieldExtension<InstanceField> {
835+
@ExtendWith(InstanceField1.Extension.class)
836+
@interface InstanceField1 {
837+
class Extension extends BaseFieldExtension<InstanceField1> {
838+
}
839+
}
840+
841+
@Target(ElementType.FIELD)
842+
@Retention(RetentionPolicy.RUNTIME)
843+
// Intentionally NOT annotated as follows
844+
// @ExtendWith(InstanceField2.Extension.class)
845+
@interface InstanceField2 {
846+
class Extension extends BaseFieldExtension<InstanceField2> {
847+
}
848+
}
849+
850+
@Target(ElementType.FIELD)
851+
@Retention(RetentionPolicy.RUNTIME)
852+
@ExtendWith(StaticField1.Extension.class)
853+
@interface StaticField1 {
854+
class Extension extends BaseFieldExtension<StaticField1> {
817855
}
818856
}
819857

820858
@Target(ElementType.FIELD)
821859
@Retention(RetentionPolicy.RUNTIME)
822-
@ExtendWith(StaticField.Extension.class)
823-
@interface StaticField {
824-
class Extension extends BaseFieldExtension<StaticField> {
860+
// Intentionally NOT annotated as follows
861+
// @ExtendWith(StaticField2.Extension.class)
862+
@interface StaticField2 {
863+
class Extension extends BaseFieldExtension<StaticField2> {
825864
}
826865
}
827866

0 commit comments

Comments
 (0)