| /* |
| * Copyright 2015-2022 the original author or authors. |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License v2.0 which |
| * accompanies this distribution and is available at |
| * |
| * https://www.eclipse.org/legal/epl-v20.html |
| */ |
| |
| package org.junit.jupiter.engine; |
| |
| import static org.assertj.core.api.Assertions.assertThat; |
| import static org.junit.jupiter.api.Assertions.fail; |
| import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; |
| import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; |
| import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; |
| import static org.junit.platform.engine.support.hierarchical.Node.ExecutionMode.CONCURRENT; |
| import static org.junit.platform.engine.support.hierarchical.Node.ExecutionMode.SAME_THREAD; |
| import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; |
| |
| import org.junit.jupiter.api.Nested; |
| import org.junit.jupiter.api.Test; |
| import org.junit.jupiter.api.TestInstance; |
| import org.junit.jupiter.api.parallel.Execution; |
| import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; |
| import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; |
| import org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor; |
| import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; |
| import org.junit.platform.engine.TestDescriptor; |
| import org.junit.platform.engine.support.hierarchical.Node; |
| import org.junit.platform.engine.support.hierarchical.Node.ExecutionMode; |
| import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; |
| |
| class DefaultExecutionModeTests extends AbstractJupiterTestEngineTests { |
| |
| @Test |
| void defaultExecutionModeIsReadFromConfigurationParameter() { |
| assertUsesExpectedExecutionMode(null, SAME_THREAD); |
| assertUsesExpectedExecutionMode(SAME_THREAD, SAME_THREAD); |
| assertUsesExpectedExecutionMode(CONCURRENT, CONCURRENT); |
| } |
| |
| private void assertUsesExpectedExecutionMode(ExecutionMode defaultExecutionMode, |
| ExecutionMode expectedExecutionMode) { |
| var engineDescriptor = discoverTestsWithDefaultExecutionMode(TestCase.class, defaultExecutionMode); |
| assertExecutionModeRecursively(engineDescriptor, expectedExecutionMode); |
| } |
| |
| @Test |
| void annotationOverridesDefaultExecutionModeToConcurrentForAllDescendants() { |
| assertUsesExpectedExecutionModeForTestClassAndItsDescendants(ConcurrentTestCase.class, null, CONCURRENT); |
| assertUsesExpectedExecutionModeForTestClassAndItsDescendants(ConcurrentTestCase.class, SAME_THREAD, CONCURRENT); |
| assertUsesExpectedExecutionModeForTestClassAndItsDescendants(ConcurrentTestCase.class, CONCURRENT, CONCURRENT); |
| } |
| |
| @Test |
| void annotationOverridesDefaultExecutionModeToSameThreadForAllDescendants() { |
| assertUsesExpectedExecutionModeForTestClassAndItsDescendants(SameThreadTestCase.class, null, SAME_THREAD); |
| assertUsesExpectedExecutionModeForTestClassAndItsDescendants(SameThreadTestCase.class, SAME_THREAD, |
| SAME_THREAD); |
| assertUsesExpectedExecutionModeForTestClassAndItsDescendants(SameThreadTestCase.class, CONCURRENT, SAME_THREAD); |
| } |
| |
| private void assertUsesExpectedExecutionModeForTestClassAndItsDescendants(Class<?> testClass, |
| ExecutionMode defaultExecutionMode, ExecutionMode expectedExecutionMode) { |
| var engineDescriptor = discoverTestsWithDefaultExecutionMode(testClass, defaultExecutionMode); |
| engineDescriptor.getChildren().forEach(child -> assertExecutionModeRecursively(child, expectedExecutionMode)); |
| } |
| |
| private void assertExecutionModeRecursively(TestDescriptor testDescriptor, ExecutionMode expectedExecutionMode) { |
| assertExecutionMode(testDescriptor, expectedExecutionMode); |
| testDescriptor.getChildren().forEach(child -> assertExecutionModeRecursively(child, expectedExecutionMode)); |
| } |
| |
| @Test |
| void methodsInTestClassesWithInstancePerClassHaveExecutionModeSameThread() { |
| var engineDescriptor = discoverTestsWithDefaultExecutionMode(SimpleTestInstancePerClassTestCase.class, |
| CONCURRENT); |
| var classDescriptor = getOnlyElement(engineDescriptor.getChildren()); |
| classDescriptor.getChildren().forEach(child -> assertExecutionModeRecursively(child, SAME_THREAD)); |
| } |
| |
| @Test |
| void methodsInNestedTestClassesWithInstancePerClassInHierarchyHaveExecutionModeSameThread() { |
| var engineDescriptor = discoverTestsWithDefaultExecutionMode(OuterTestCase.class, CONCURRENT); |
| var outerTestCaseClassDescriptor = firstChild(engineDescriptor, ClassTestDescriptor.class); |
| var outerTestMethodDescriptor = firstChild(outerTestCaseClassDescriptor, TestMethodTestDescriptor.class); |
| var level1NestedClassDescriptor = firstChild(outerTestCaseClassDescriptor, NestedClassTestDescriptor.class); |
| var level1TestMethodDescriptor = firstChild(level1NestedClassDescriptor, TestMethodTestDescriptor.class); |
| var level2NestedClassDescriptor = firstChild(level1NestedClassDescriptor, NestedClassTestDescriptor.class); |
| var level2TestMethodDescriptor = firstChild(level2NestedClassDescriptor, TestMethodTestDescriptor.class); |
| var level3NestedClassDescriptor = firstChild(level2NestedClassDescriptor, NestedClassTestDescriptor.class); |
| var level3TestMethodDescriptor = firstChild(level3NestedClassDescriptor, TestMethodTestDescriptor.class); |
| |
| assertExecutionMode(outerTestCaseClassDescriptor, CONCURRENT); |
| assertExecutionMode(outerTestMethodDescriptor, CONCURRENT); |
| assertExecutionMode(level1NestedClassDescriptor, CONCURRENT); |
| assertExecutionMode(level1TestMethodDescriptor, CONCURRENT); |
| assertExecutionMode(level2NestedClassDescriptor, CONCURRENT); |
| assertExecutionMode(level2TestMethodDescriptor, SAME_THREAD); |
| assertExecutionMode(level3NestedClassDescriptor, SAME_THREAD); |
| assertExecutionMode(level3TestMethodDescriptor, SAME_THREAD); |
| } |
| |
| private JupiterEngineDescriptor discoverTestsWithDefaultExecutionMode(Class<?> testClass, |
| ExecutionMode executionMode) { |
| LauncherDiscoveryRequestBuilder request = request().selectors(selectClass(testClass)); |
| if (executionMode != null) { |
| request.configurationParameter(Constants.DEFAULT_PARALLEL_EXECUTION_MODE, executionMode.name()); |
| } |
| return (JupiterEngineDescriptor) discoverTests(request.build()); |
| } |
| |
| private static void assertExecutionMode(TestDescriptor testDescriptor, ExecutionMode expectedExecutionMode) { |
| assertThat(((Node<?>) testDescriptor).getExecutionMode()) // |
| .describedAs("ExecutionMode for %s", testDescriptor) // |
| .isEqualTo(expectedExecutionMode); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T extends TestDescriptor> T firstChild(TestDescriptor engineDescriptor, Class<T> testDescriptorClass) { |
| return (T) engineDescriptor.getChildren().stream() // |
| .filter(testDescriptorClass::isInstance) // |
| .findFirst() // |
| .orElseGet(() -> fail("No child of type " + testDescriptorClass + " found")); |
| } |
| |
| static class TestCase { |
| |
| @Test |
| void test() { |
| } |
| |
| @Nested |
| class NestedTestCase { |
| |
| @Test |
| void test() { |
| } |
| |
| } |
| |
| } |
| |
| @TestInstance(PER_CLASS) |
| static class SimpleTestInstancePerClassTestCase extends TestCase { |
| } |
| |
| @Execution(org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT) |
| static class ConcurrentTestCase extends TestCase { |
| } |
| |
| @Execution(org.junit.jupiter.api.parallel.ExecutionMode.SAME_THREAD) |
| static class SameThreadTestCase extends TestCase { |
| } |
| |
| static class OuterTestCase { |
| @Nested |
| class LevelOne { |
| @Nested |
| @TestInstance(PER_CLASS) |
| class LevelTwo { |
| @Nested |
| class LevelThree { |
| @Test |
| void test() { |
| } |
| } |
| |
| @Test |
| void test() { |
| } |
| } |
| |
| @Test |
| void test() { |
| } |
| } |
| |
| @Test |
| void test() { |
| } |
| } |
| |
| } |