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,15 @@ 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
+ List <DiscoveryIssue > discoveryIssues = this .lifecycleMethods .discoveryIssues ;
138
+ discoveryIssues .forEach (reporter ::reportIssue );
139
+ discoveryIssues .clear ();
140
+ }
141
+
130
142
// --- Node ----------------------------------------------------------------
131
143
132
144
@ Override
@@ -166,24 +178,15 @@ public final JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext
166
178
registerExtensionsFromConstructorParameters (registry , getTestClass ());
167
179
}
168
180
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 ));
181
+ this .lifecycleMethods .beforeAll .forEach (method -> registerExtensionsFromExecutableParameters (registry , method ));
179
182
// Since registerBeforeEachMethodAdapters() and registerAfterEachMethodAdapters() also
180
183
// invoke registerExtensionsFromExecutableParameters(), we invoke those methods before
181
184
// invoking registerExtensionsFromExecutableParameters() for @AfterAll methods,
182
185
// thereby ensuring proper registration order for extensions registered via @ExtendWith
183
186
// on parameters in lifecycle methods.
184
187
registerBeforeEachMethodAdapters (registry );
185
188
registerAfterEachMethodAdapters (registry );
186
- this .afterAllMethods .forEach (method -> registerExtensionsFromExecutableParameters (registry , method ));
189
+ this .lifecycleMethods . afterAll .forEach (method -> registerExtensionsFromExecutableParameters (registry , method ));
187
190
registerExtensionsFromInstanceFields (registry , getTestClass ());
188
191
189
192
ThrowableCollector throwableCollector = createThrowableCollector ();
@@ -258,6 +261,13 @@ public final void after(JupiterEngineExecutionContext context) {
258
261
}
259
262
}
260
263
264
+ @ Override
265
+ public void cleanUp (JupiterEngineExecutionContext context ) throws Exception {
266
+ super .cleanUp (context );
267
+ this .lifecycleMethods = null ;
268
+ this .testInstanceFactory = null ;
269
+ }
270
+
261
271
private TestInstanceFactory resolveTestInstanceFactory (ExtensionRegistry registry ) {
262
272
List <TestInstanceFactory > factories = registry .getExtensions (TestInstanceFactory .class );
263
273
@@ -410,7 +420,7 @@ private void invokeBeforeAllMethods(JupiterEngineExecutionContext context) {
410
420
ThrowableCollector throwableCollector = context .getThrowableCollector ();
411
421
Object testInstance = extensionContext .getTestInstance ().orElse (null );
412
422
413
- for (Method method : this .beforeAllMethods ) {
423
+ for (Method method : this .lifecycleMethods . beforeAll ) {
414
424
throwableCollector .execute (() -> {
415
425
try {
416
426
executableInvoker .invoke (method , testInstance , extensionContext , registry ,
@@ -439,7 +449,7 @@ private void invokeAfterAllMethods(JupiterEngineExecutionContext context) {
439
449
ThrowableCollector throwableCollector = context .getThrowableCollector ();
440
450
Object testInstance = extensionContext .getTestInstance ().orElse (null );
441
451
442
- this .afterAllMethods .forEach (method -> throwableCollector .execute (() -> {
452
+ this .lifecycleMethods . afterAll .forEach (method -> throwableCollector .execute (() -> {
443
453
try {
444
454
executableInvoker .invoke (method , testInstance , extensionContext , registry ,
445
455
ReflectiveInterceptorCall .ofVoidMethod (InvocationInterceptor ::interceptAfterAllMethod ));
@@ -472,17 +482,13 @@ private boolean isPerClassLifecycle(JupiterEngineExecutionContext context) {
472
482
}
473
483
474
484
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 );
485
+ registerMethodsAsExtensions (this .lifecycleMethods .beforeEach , registrar ,
486
+ this ::synthesizeBeforeEachMethodAdapter );
479
487
}
480
488
481
489
private void registerAfterEachMethodAdapters (ExtensionRegistrar registrar ) {
482
490
// 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
- }));
491
+ List <Method > afterEachMethods = new ArrayList <>(this .lifecycleMethods .afterEach );
486
492
487
493
// Since the bottom-up ordering of afterEachMethods will later be reversed when the
488
494
// synthesized AfterEachMethodAdapters are executed within TestMethodTestDescriptor,
@@ -523,6 +529,7 @@ private void invokeMethodInExtensionContext(Method method, ExtensionContext cont
523
529
}
524
530
525
531
protected static class ClassInfo {
532
+
526
533
final Class <?> testClass ;
527
534
final Set <TestTag > tags ;
528
535
final Lifecycle lifecycle ;
@@ -538,4 +545,23 @@ protected static class ClassInfo {
538
545
}
539
546
}
540
547
548
+ private static class LifecycleMethods {
549
+
550
+ private final List <DiscoveryIssue > discoveryIssues = new ArrayList <>();
551
+
552
+ private final List <Method > beforeAll ;
553
+ private final List <Method > afterAll ;
554
+ private final List <Method > beforeEach ;
555
+ private final List <Method > afterEach ;
556
+
557
+ LifecycleMethods (ClassInfo classInfo ) {
558
+ Class <?> testClass = classInfo .testClass ;
559
+ boolean requireStatic = classInfo .lifecycle == Lifecycle .PER_METHOD ;
560
+ this .beforeAll = findBeforeAllMethods (testClass , requireStatic , discoveryIssues ::add );
561
+ this .afterAll = findAfterAllMethods (testClass , requireStatic , discoveryIssues ::add );
562
+ this .beforeEach = findBeforeEachMethods (testClass , discoveryIssues ::add );
563
+ this .afterEach = findAfterEachMethods (testClass , discoveryIssues ::add );
564
+ }
565
+ }
566
+
541
567
}
0 commit comments