Fix logic for validating @RecordApplicationEvents config

Prior to this commit, the SpringExtension looked up the
TestInstance.Lifecycle and ExecutionMode using
TestContextAnnotationUtils; however, using TestContextAnnotationUtils is
problematic since the TestInstance.Lifecycle and ExecutionMode can be
configured globally via configuration parameters instead of locally via
the @TestInstance and @Execution annotations.

This commit addresses these issues by looking up the
TestInstance.Lifecycle and ExecutionMode via JUnit Jupiter's
ExtensionContext which takes into account both global and local
configuration.

See gh-30020
This commit is contained in:
Sam Brannen
2023-05-13 19:17:18 +02:00
parent 5e1a4740d7
commit f3f3dc693a
2 changed files with 35 additions and 42 deletions

View File

@@ -32,8 +32,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.platform.engine.TestExecutionResult;
import org.junit.platform.testkit.engine.EngineExecutionResults;
import org.junit.platform.testkit.engine.EngineTestKit;
@@ -68,28 +66,27 @@ class ParallelApplicationEventsIntegrationTests {
void rejectTestsInParallelWithInstancePerClassAndRecordApplicationEvents() {
Class<?> testClass = TestInstancePerClassTestCase.class;
final EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
.selectors(selectClass(testClass))//
.configurationParameter("junit.jupiter.execution.parallel.enabled", "true")//
.configurationParameter("junit.jupiter.execution.parallel.mode.default", "concurrent")//
.configurationParameter("junit.jupiter.execution.parallel.config.dynamic.factor", "10")//
.execute();
//extract the messages from failed TextExecutionResults
// extract the messages from failed TextExecutionResults
assertThat(results.containerEvents().failed()//
.stream().map(e -> e.getRequiredPayload(TestExecutionResult.class)//
.getThrowable().get().getMessage()))//
.map(e -> e.getRequiredPayload(TestExecutionResult.class).getThrowable().get().getMessage()))//
.singleElement(InstanceOfAssertFactories.STRING)
.isEqualToIgnoringNewLines("""
Test classes or inner classes that @RecordApplicationEvents\s
must not be run in parallel with the @TestInstance(Lifecycle.PER_CLASS) configuration.\s
Use either @Execution(SAME_THREAD), @TestInstance(PER_METHOD) or disable parallel\s
execution altogether. Note that when recording events in parallel, one might see events\s
published by other tests as the application context can be common.
""");
.isEqualTo("""
Test classes or @Nested test classes that @RecordApplicationEvents must not be run \
in parallel with the @TestInstance(PER_CLASS) lifecycle mode. Configure either \
@Execution(SAME_THREAD) or @TestInstance(PER_METHOD) semantics, or disable parallel \
execution altogether. Note that when recording events in parallel, one might see events \
published by other tests since the application context may be shared.""");
}
@Test
void executeTestsInParallelInstancePerMethod() {
void executeTestsInParallelWithInstancePerMethod() {
Class<?> testClass = TestInstancePerMethodTestCase.class;
Events testEvents = EngineTestKit.engine("junit-jupiter")//
.selectors(selectClass(testClass))//
@@ -97,7 +94,7 @@ class ParallelApplicationEventsIntegrationTests {
.configurationParameter("junit.jupiter.execution.parallel.config.dynamic.factor", "10")//
.execute()//
.testEvents();
//list failed events in case of test errors to get a sense of which tests failed
// list failed events in case of test errors to get a sense of which tests failed
Events failedTests = testEvents.failed();
if (failedTests.count() > 0) {
failedTests.debug();
@@ -141,7 +138,6 @@ class ParallelApplicationEventsIntegrationTests {
@SpringJUnitConfig
@RecordApplicationEvents
@Execution(ExecutionMode.CONCURRENT)
@TestInstance(Lifecycle.PER_METHOD)
static class TestInstancePerMethodTestCase {
@@ -211,7 +207,7 @@ class ParallelApplicationEventsIntegrationTests {
@Test
void asyncPublication(ApplicationEvents events) throws InterruptedException {
final ExecutorService executorService = Executors.newSingleThreadExecutor();
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> this.context.publishEvent("asyncPublication"));
executorService.shutdown();
executorService.awaitTermination(10, TimeUnit.SECONDS);