1010
1111package org .junit .jupiter .engine .extension ;
1212
13+ import static java .util .function .Function .identity ;
14+ import static java .util .function .Predicate .isEqual ;
1315import static org .assertj .core .api .Assertions .assertThat ;
1416import static org .junit .jupiter .api .Assertions .assertEquals ;
1517import static org .junit .jupiter .api .Assertions .fail ;
2224
2325import java .lang .reflect .Constructor ;
2426import java .lang .reflect .Method ;
25- import java .util .EnumSet ;
27+ import java .util .Arrays ;
28+ import java .util .Collection ;
29+ import java .util .List ;
30+ import java .util .function .UnaryOperator ;
2631import java .util .stream .Stream ;
2732
2833import org .junit .jupiter .api .AfterAll ;
2934import org .junit .jupiter .api .AfterEach ;
3035import org .junit .jupiter .api .BeforeAll ;
3136import org .junit .jupiter .api .BeforeEach ;
3237import org .junit .jupiter .api .DynamicTest ;
38+ import org .junit .jupiter .api .MethodOrderer ;
39+ import org .junit .jupiter .api .Order ;
3340import org .junit .jupiter .api .RepeatedTest ;
3441import org .junit .jupiter .api .Test ;
3542import org .junit .jupiter .api .TestFactory ;
43+ import org .junit .jupiter .api .TestMethodOrder ;
3644import org .junit .jupiter .api .TestReporter ;
3745import org .junit .jupiter .api .extension .DynamicTestInvocationContext ;
3846import org .junit .jupiter .api .extension .ExtendWith ;
4250import org .junit .jupiter .api .extension .ReflectiveInvocationContext ;
4351import org .junit .jupiter .api .extension .RegisterExtension ;
4452import org .junit .jupiter .engine .AbstractJupiterTestEngineTests ;
45- import org .junit .jupiter .params .ParameterizedTest ;
46- import org .junit .jupiter .params .provider .EnumSource ;
4753import org .junit .platform .commons .JUnitException ;
4854import org .junit .platform .engine .reporting .ReportEntry ;
4955import org .junit .platform .testkit .engine .EngineExecutionResults ;
@@ -130,28 +136,76 @@ void test() {
130136 }
131137 }
132138
133- @ ParameterizedTest (name = "{0}" )
134- @ EnumSource (InvocationType .class )
135- void callsInterceptors (InvocationType invocationType ) {
139+ @ TestFactory
140+ Stream <DynamicTest > callsInterceptors () {
136141 var results = executeTestsForClass (TestCaseWithThreeInterceptors .class );
137142
138143 results .testEvents ().assertStatistics (stats -> stats .failed (0 ).succeeded (3 ));
139144
140- assertThat (getEvents (results , EnumSet .of (invocationType )).distinct ()) //
141- .containsExactly ("before:foo" , "before:bar" , "before:baz" , "test" , "after:baz" , "after:bar" ,
142- "after:foo" );
145+ return Arrays .stream (InvocationType .values ()) //
146+ .map (it -> dynamicTest (it .name (), () -> verifyEvents (results , it )));
143147 }
144148
145- private Stream <String > getEvents (EngineExecutionResults results , EnumSet <InvocationType > types ) {
146- return results .allEvents ().reportingEntryPublished () //
147- .map (event -> event .getPayload (ReportEntry .class ).orElseThrow ()) //
148- .map (ReportEntry ::getKeyValuePairs ) //
149- .filter (map -> map .keySet ().stream ().map (InvocationType ::valueOf ).anyMatch (types ::contains )) //
150- .flatMap (map -> map .values ().stream ());
149+ private void verifyEvents (EngineExecutionResults results , InvocationType invocationType ) {
150+ var beforeEvents = List .of ("before:foo" , "before:bar" , "before:baz" );
151+ var testEvent = List .of ("test" );
152+ var afterEvents = List .of ("after:baz" , "after:bar" , "after:foo" );
153+ var allEvents = Stream .of (beforeEvents , testEvent , afterEvents ).flatMap (Collection ::stream ).toList ();
154+ String testClassName = TestCaseWithThreeInterceptors .class .getName ();
155+
156+ var expectedElements = switch (invocationType ) {
157+ case BEFORE_ALL , AFTER_ALL -> prefixed (allEvents , testClassName );
158+ case CONSTRUCTOR -> concatStreams (
159+ prefixed (allEvents , it -> it .endsWith (":bar" ) ? testClassName : "test(TestReporter)" ),
160+ prefixed (allEvents , it -> it .endsWith (":bar" ) ? testClassName : "testTemplate(TestReporter)[1]" ),
161+ prefixed (allEvents , it -> it .endsWith (":bar" ) ? testClassName : "testFactory(TestReporter)" ));
162+ case BEFORE_EACH , AFTER_EACH -> concatStreams (prefixed (allEvents , "test(TestReporter)" ),
163+ prefixed (allEvents , "testTemplate(TestReporter)[1]" ), prefixed (allEvents , "testFactory(TestReporter)" ));
164+ case TEST_METHOD -> prefixed (allEvents , "test(TestReporter)" );
165+ case TEST_TEMPLATE_METHOD -> prefixed (allEvents , "testTemplate(TestReporter)[1]" );
166+ case TEST_FACTORY_METHOD -> prefixed (allEvents , "testFactory(TestReporter)" );
167+ case DYNAMIC_TEST -> concatStreams (prefixed (beforeEvents , "testFactory(TestReporter)[1]" ),
168+ prefixed (testEvent , "testFactory(TestReporter)" ),
169+ prefixed (afterEvents , "testFactory(TestReporter)[1]" ));
170+ };
171+
172+ assertThat (getEvents (results , invocationType )) //
173+ .containsExactlyElementsOf (expectedElements .toList ());
174+ }
175+
176+ @ SafeVarargs
177+ @ SuppressWarnings ("varargs" )
178+ private static <T > Stream <T > concatStreams (Stream <T >... items ) {
179+ return Stream .of (items ).flatMap (identity ());
180+ }
181+
182+ private static Stream <String > prefixed (List <String > values , String prefix ) {
183+ return prefixed (values , __ -> prefix );
184+ }
185+
186+ private static Stream <String > prefixed (List <String > values , UnaryOperator <String > prefixGenerator ) {
187+ return values .stream () //
188+ .map (it -> "[%s] %s" .formatted (prefixGenerator .apply (it ), it ));
189+ }
190+
191+ private Stream <String > getEvents (EngineExecutionResults results , InvocationType invocationType ) {
192+ return results .allEvents ().reportingEntryPublished ().stream () //
193+ .flatMap (event -> {
194+ var reportEntry = event .getPayload (ReportEntry .class ).orElseThrow ();
195+ var keyValuePairs = reportEntry .getKeyValuePairs ();
196+ if (keyValuePairs .keySet ().stream () //
197+ .map (InvocationType ::valueOf ) //
198+ .anyMatch (isEqual (invocationType ))) {
199+ return keyValuePairs .values ().stream () //
200+ .map (it -> "[%s] %s" .formatted (event .getTestDescriptor ().getLegacyReportingName (), it ));
201+ }
202+ return Stream .empty ();
203+ });
151204 }
152205
153206 @ SuppressWarnings ("JUnitMalformedDeclaration" )
154207 @ ExtendWith ({ FooInvocationInterceptor .class , BarInvocationInterceptor .class , BazInvocationInterceptor .class })
208+ @ TestMethodOrder (MethodOrderer .OrderAnnotation .class )
155209 static class TestCaseWithThreeInterceptors {
156210
157211 public TestCaseWithThreeInterceptors (TestReporter reporter ) {
@@ -169,16 +223,19 @@ void beforeEach(TestReporter reporter) {
169223 publish (reporter , InvocationType .BEFORE_EACH );
170224 }
171225
226+ @ Order (1 )
172227 @ Test
173228 void test (TestReporter reporter ) {
174229 publish (reporter , InvocationType .TEST_METHOD );
175230 }
176231
232+ @ Order (2 )
177233 @ RepeatedTest (1 )
178234 void testTemplate (TestReporter reporter ) {
179235 publish (reporter , InvocationType .TEST_TEMPLATE_METHOD );
180236 }
181237
238+ @ Order (3 )
182239 @ TestFactory
183240 DynamicTest testFactory (TestReporter reporter ) {
184241 publish (reporter , InvocationType .TEST_FACTORY_METHOD );
@@ -224,6 +281,11 @@ abstract static class ReportingInvocationInterceptor implements InvocationInterc
224281 this .name = name ;
225282 }
226283
284+ @ Override
285+ public ExtensionContextScope getTestInstantiationExtensionContextScope (ExtensionContext rootContext ) {
286+ return ExtensionContextScope .TEST_METHOD ;
287+ }
288+
227289 @ Override
228290 public void interceptBeforeAllMethod (Invocation <Void > invocation ,
229291 ReflectiveInvocationContext <Method > invocationContext , ExtensionContext extensionContext )
@@ -299,8 +361,8 @@ public void interceptDynamicTest(Invocation<Void> invocation, DynamicTestInvocat
299361 assertThat (invocationContext .getExecutable ()).isNotNull ();
300362 assertThat (extensionContext .getUniqueId ()).isNotBlank ();
301363 assertThat (extensionContext .getElement ()).isEmpty ();
302- assertThat (extensionContext .getParent ().flatMap (ExtensionContext ::getTestMethod )). contains (
303- testClass .getDeclaredMethod ("testFactory" , TestReporter .class ));
364+ assertThat (extensionContext .getParent ().flatMap (ExtensionContext ::getTestMethod )) //
365+ . contains ( testClass .getDeclaredMethod ("testFactory" , TestReporter .class ));
304366 reportAndProceed (invocation , extensionContext , InvocationType .DYNAMIC_TEST );
305367 }
306368
@@ -350,6 +412,12 @@ static class BarInvocationInterceptor extends ReportingInvocationInterceptor {
350412 BarInvocationInterceptor () {
351413 super ("bar" );
352414 }
415+
416+ @ SuppressWarnings ("deprecation" )
417+ @ Override
418+ public ExtensionContextScope getTestInstantiationExtensionContextScope (ExtensionContext rootContext ) {
419+ return ExtensionContextScope .DEFAULT ;
420+ }
353421 }
354422
355423 static class BazInvocationInterceptor extends ReportingInvocationInterceptor {
0 commit comments