71
71
import org .junit .platform .commons .util .ReflectionUtils ;
72
72
import org .junit .platform .commons .util .StringUtils ;
73
73
import org .junit .platform .commons .util .UnrecoverableExceptions ;
74
+ import org .junit .platform .engine .DiscoveryIssue ;
74
75
import org .junit .platform .engine .TestDescriptor ;
75
76
import org .junit .platform .engine .TestTag ;
76
77
import org .junit .platform .engine .UniqueId ;
77
78
import org .junit .platform .engine .support .descriptor .ClassSource ;
79
+ import org .junit .platform .engine .support .discovery .DiscoveryIssueReporter ;
78
80
import org .junit .platform .engine .support .hierarchical .ThrowableCollector ;
79
81
80
82
/**
84
86
*/
85
87
@ API (status = INTERNAL , since = "5.5" )
86
88
public abstract class ClassBasedTestDescriptor extends JupiterTestDescriptor
87
- implements ResourceLockAware , TestClassAware {
89
+ implements ResourceLockAware , TestClassAware , Validatable {
88
90
89
91
private static final InterceptingExecutableInvoker executableInvoker = new InterceptingExecutableInvoker ();
90
92
91
93
protected final ClassInfo classInfo ;
92
94
95
+ private LifecycleMethods lifecycleMethods ;
93
96
private TestInstanceFactory testInstanceFactory ;
94
- private List <Method > beforeAllMethods ;
95
- private List <Method > afterAllMethods ;
96
97
97
98
ClassBasedTestDescriptor (UniqueId uniqueId , Class <?> testClass , Supplier <String > displayNameSupplier ,
98
99
JupiterConfiguration configuration ) {
99
100
super (uniqueId , testClass , displayNameSupplier , ClassSource .from (testClass ), configuration );
100
101
101
102
this .classInfo = new ClassInfo (testClass , configuration );
103
+ this .lifecycleMethods = new LifecycleMethods (this .classInfo );
102
104
}
103
105
104
106
ClassBasedTestDescriptor (UniqueId uniqueId , Class <?> testClass , String displayName ,
105
107
JupiterConfiguration configuration ) {
106
108
super (uniqueId , displayName , ClassSource .from (testClass ), configuration );
107
109
108
110
this .classInfo = new ClassInfo (testClass , configuration );
111
+ this .lifecycleMethods = new LifecycleMethods (this .classInfo );
109
112
}
110
113
111
114
// --- TestClassAware ------------------------------------------------------
@@ -127,6 +130,13 @@ public final String getLegacyReportingName() {
127
130
return getTestClass ().getName ();
128
131
}
129
132
133
+ // --- Validatable ---------------------------------------------------------
134
+
135
+ @ Override
136
+ public void validate (DiscoveryIssueReporter reporter ) {
137
+ this .lifecycleMethods .discoveryIssues .forEach (reporter ::reportIssue );
138
+ }
139
+
130
140
// --- Node ----------------------------------------------------------------
131
141
132
142
@ Override
@@ -166,24 +176,15 @@ public final JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext
166
176
registerExtensionsFromConstructorParameters (registry , getTestClass ());
167
177
}
168
178
169
- this .beforeAllMethods = findBeforeAllMethods (getTestClass (), this .classInfo .lifecycle == Lifecycle .PER_METHOD ,
170
- issue -> {
171
- throw new JUnitException (issue .message ());
172
- });
173
- this .afterAllMethods = findAfterAllMethods (getTestClass (), this .classInfo .lifecycle == Lifecycle .PER_METHOD ,
174
- issue -> {
175
- throw new JUnitException (issue .message ());
176
- });
177
-
178
- this .beforeAllMethods .forEach (method -> registerExtensionsFromExecutableParameters (registry , method ));
179
+ this .lifecycleMethods .beforeAll .forEach (method -> registerExtensionsFromExecutableParameters (registry , method ));
179
180
// Since registerBeforeEachMethodAdapters() and registerAfterEachMethodAdapters() also
180
181
// invoke registerExtensionsFromExecutableParameters(), we invoke those methods before
181
182
// invoking registerExtensionsFromExecutableParameters() for @AfterAll methods,
182
183
// thereby ensuring proper registration order for extensions registered via @ExtendWith
183
184
// on parameters in lifecycle methods.
184
185
registerBeforeEachMethodAdapters (registry );
185
186
registerAfterEachMethodAdapters (registry );
186
- this .afterAllMethods .forEach (method -> registerExtensionsFromExecutableParameters (registry , method ));
187
+ this .lifecycleMethods . afterAll .forEach (method -> registerExtensionsFromExecutableParameters (registry , method ));
187
188
registerExtensionsFromInstanceFields (registry , getTestClass ());
188
189
189
190
ThrowableCollector throwableCollector = createThrowableCollector ();
@@ -258,6 +259,13 @@ public final void after(JupiterEngineExecutionContext context) {
258
259
}
259
260
}
260
261
262
+ @ Override
263
+ public void cleanUp (JupiterEngineExecutionContext context ) throws Exception {
264
+ super .cleanUp (context );
265
+ this .lifecycleMethods = null ;
266
+ this .testInstanceFactory = null ;
267
+ }
268
+
261
269
private TestInstanceFactory resolveTestInstanceFactory (ExtensionRegistry registry ) {
262
270
List <TestInstanceFactory > factories = registry .getExtensions (TestInstanceFactory .class );
263
271
@@ -410,7 +418,7 @@ private void invokeBeforeAllMethods(JupiterEngineExecutionContext context) {
410
418
ThrowableCollector throwableCollector = context .getThrowableCollector ();
411
419
Object testInstance = extensionContext .getTestInstance ().orElse (null );
412
420
413
- for (Method method : this .beforeAllMethods ) {
421
+ for (Method method : this .lifecycleMethods . beforeAll ) {
414
422
throwableCollector .execute (() -> {
415
423
try {
416
424
executableInvoker .invoke (method , testInstance , extensionContext , registry ,
@@ -439,7 +447,7 @@ private void invokeAfterAllMethods(JupiterEngineExecutionContext context) {
439
447
ThrowableCollector throwableCollector = context .getThrowableCollector ();
440
448
Object testInstance = extensionContext .getTestInstance ().orElse (null );
441
449
442
- this .afterAllMethods .forEach (method -> throwableCollector .execute (() -> {
450
+ this .lifecycleMethods . afterAll .forEach (method -> throwableCollector .execute (() -> {
443
451
try {
444
452
executableInvoker .invoke (method , testInstance , extensionContext , registry ,
445
453
ReflectiveInterceptorCall .ofVoidMethod (InvocationInterceptor ::interceptAfterAllMethod ));
@@ -472,17 +480,13 @@ private boolean isPerClassLifecycle(JupiterEngineExecutionContext context) {
472
480
}
473
481
474
482
private void registerBeforeEachMethodAdapters (ExtensionRegistrar registrar ) {
475
- List <Method > beforeEachMethods = findBeforeEachMethods (getTestClass (), issue -> {
476
- throw new JUnitException (issue .message ());
477
- });
478
- registerMethodsAsExtensions (beforeEachMethods , registrar , this ::synthesizeBeforeEachMethodAdapter );
483
+ registerMethodsAsExtensions (this .lifecycleMethods .beforeEach , registrar ,
484
+ this ::synthesizeBeforeEachMethodAdapter );
479
485
}
480
486
481
487
private void registerAfterEachMethodAdapters (ExtensionRegistrar registrar ) {
482
488
// Make a local copy since findAfterEachMethods() returns an immutable list.
483
- List <Method > afterEachMethods = new ArrayList <>(findAfterEachMethods (getTestClass (), issue -> {
484
- throw new JUnitException (issue .message ());
485
- }));
489
+ List <Method > afterEachMethods = new ArrayList <>(this .lifecycleMethods .afterEach );
486
490
487
491
// Since the bottom-up ordering of afterEachMethods will later be reversed when the
488
492
// synthesized AfterEachMethodAdapters are executed within TestMethodTestDescriptor,
@@ -523,6 +527,7 @@ private void invokeMethodInExtensionContext(Method method, ExtensionContext cont
523
527
}
524
528
525
529
protected static class ClassInfo {
530
+
526
531
final Class <?> testClass ;
527
532
final Set <TestTag > tags ;
528
533
final Lifecycle lifecycle ;
@@ -538,4 +543,23 @@ protected static class ClassInfo {
538
543
}
539
544
}
540
545
546
+ private static class LifecycleMethods {
547
+
548
+ private final List <DiscoveryIssue > discoveryIssues = new ArrayList <>();
549
+
550
+ private final List <Method > beforeAll ;
551
+ private final List <Method > afterAll ;
552
+ private final List <Method > beforeEach ;
553
+ private final List <Method > afterEach ;
554
+
555
+ LifecycleMethods (ClassInfo classInfo ) {
556
+ Class <?> testClass = classInfo .testClass ;
557
+ boolean requireStatic = classInfo .lifecycle == Lifecycle .PER_METHOD ;
558
+ this .beforeAll = findBeforeAllMethods (testClass , requireStatic , discoveryIssues ::add );
559
+ this .afterAll = findAfterAllMethods (testClass , requireStatic , discoveryIssues ::add );
560
+ this .beforeEach = findBeforeEachMethods (testClass , discoveryIssues ::add );
561
+ this .afterEach = findAfterEachMethods (testClass , discoveryIssues ::add );
562
+ }
563
+ }
564
+
541
565
}
0 commit comments