diff --git a/build.gradle b/build.gradle index 05467b46b8f..0de4cd70f03 100644 --- a/build.gradle +++ b/build.gradle @@ -74,5 +74,4 @@ configure(rootProject) { task wrapper(type: Wrapper) { gradleVersion = '2.8' } - } diff --git a/junit-commons/src/main/java/org/junit/gen5/commons/util/ReflectionUtils.java b/junit-commons/src/main/java/org/junit/gen5/commons/util/ReflectionUtils.java new file mode 100644 index 00000000000..2168580145c --- /dev/null +++ b/junit-commons/src/main/java/org/junit/gen5/commons/util/ReflectionUtils.java @@ -0,0 +1,32 @@ +package org.junit.gen5.commons.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * @author Stefan Bechtold + * @since 5.0 + */ +public class ReflectionUtils { + private ReflectionUtils() { + /* no-op */ + } + + public static T newInstance(Class clazz) + throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { + Constructor constructor = clazz.getDeclaredConstructor(); + if (!constructor.isAccessible()) { + constructor.setAccessible(true); + } + return constructor.newInstance(); + } + + public static T invokeMethod(Method method, Object testInstance) + throws IllegalAccessException, InvocationTargetException { + if (!method.isAccessible()) { + method.setAccessible(true); + } + return (T) method.invoke(testInstance); + } +} \ No newline at end of file diff --git a/junit-console/src/main/java/org/junit/gen5/console/ColoredPrintingTestListener.java b/junit-console/src/main/java/org/junit/gen5/console/ColoredPrintingTestListener.java index 9e49fd10e43..81794c0dc5a 100644 --- a/junit-console/src/main/java/org/junit/gen5/console/ColoredPrintingTestListener.java +++ b/junit-console/src/main/java/org/junit/gen5/console/ColoredPrintingTestListener.java @@ -1,72 +1,96 @@ package org.junit.gen5.console; -import java.io.PrintStream; -import org.junit.gen5.launcher.TestIdentifier; -import org.junit.gen5.launcher.TestListener; +import org.junit.gen5.engine.TestDescriptor; +import org.junit.gen5.engine.TestListener; + +import java.io.PrintStream; /** * @author Stefan Bechtold * @since 5.0 */ public class ColoredPrintingTestListener implements TestListener { - public static final String ANSI_RESET = "\u001B[0m"; - public static final String ANSI_BLACK = "\u001B[30m"; - public static final String ANSI_RED = "\u001B[31m"; - public static final String ANSI_GREEN = "\u001B[32m"; - public static final String ANSI_YELLOW = "\u001B[33m"; - public static final String ANSI_BLUE = "\u001B[34m"; - public static final String ANSI_PURPLE = "\u001B[35m"; - public static final String ANSI_CYAN = "\u001B[36m"; - public static final String ANSI_WHITE = "\u001B[37m"; - - private final PrintStream out; - - public ColoredPrintingTestListener(PrintStream out) { - this.out = out; - } - - @Override - public void testFound(TestIdentifier testIdentifier) { - out.print(ANSI_GREEN); - out.format("Test found: %s", testIdentifier.toString()); - out.println(ANSI_RESET); - } - - @Override - public void testStarted(TestIdentifier testIdentifier) { - out.print(ANSI_GREEN); - out.format("Test started: %s", testIdentifier.toString()); - out.println(ANSI_RESET); - } - - @Override - public void testSkipped(TestIdentifier testIdentifier, Throwable t) { - out.print(ANSI_YELLOW); - out.format("Test skipped: %s\n=> Exception: %s", testIdentifier.toString(), - (t != null) ? t.getLocalizedMessage() : "none"); - out.println(ANSI_RESET); - } - - @Override - public void testAborted(TestIdentifier testIdentifier, Throwable t) { - out.print(ANSI_YELLOW); - out.format("Test aborted: %s\n=> Exception: %s", testIdentifier.toString(), - (t != null) ? t.getLocalizedMessage() : "none"); - out.println(ANSI_RESET); - } - - @Override - public void testFailed(TestIdentifier testIdentifier, Throwable t) { - out.print(ANSI_RED); - out.format("Test failed: %s\n=> Exception: %s", testIdentifier.toString(), t.getLocalizedMessage()); - out.println(ANSI_RESET); - } - - @Override - public void testSucceeded(TestIdentifier testIdentifier) { - out.print(ANSI_GREEN); - out.format("Test succeeded: %s", testIdentifier.toString()); - out.println(ANSI_RESET); - } + public static final String ANSI_RESET = "\u001B[0m"; + public static final String ANSI_BLACK = "\u001B[30m"; + public static final String ANSI_RED = "\u001B[31m"; + public static final String ANSI_GREEN = "\u001B[32m"; + public static final String ANSI_YELLOW = "\u001B[33m"; + public static final String ANSI_BLUE = "\u001B[34m"; + public static final String ANSI_PURPLE = "\u001B[35m"; + public static final String ANSI_CYAN = "\u001B[36m"; + public static final String ANSI_WHITE = "\u001B[37m"; + + private final PrintStream out; + + public ColoredPrintingTestListener(PrintStream out) { + this.out = out; + } + + @Override + public void testExecutionStarted() { + out.println("Test execution started."); + } + + @Override + public void testExecutionPaused() { + out.println("Test execution paused."); + } + + @Override + public void testExecutionRestarted() { + out.println("Test execution continued."); + } + + @Override + public void testExecutionStopped() { + out.println("Test execution canceled."); + } + + @Override + public void testExecutionFinished() { + out.println(ANSI_RESET); + } + + @Override + public void testFound(TestDescriptor testDescriptor) { + out.print(ANSI_GREEN); + out.format("Test found: %s", testDescriptor.toString()); + out.println(ANSI_RESET); + } + + @Override + public void testStarted(TestDescriptor testDescriptor) { + out.print(ANSI_GREEN); + out.format("Test started: %s", testDescriptor.toString()); + out.println(ANSI_RESET); + } + + @Override + public void testSkipped(TestDescriptor testDescriptor, Throwable t) { + out.print(ANSI_YELLOW); + out.format("Test skipped: %s\n=> Exception: %s", testDescriptor.toString(), (t != null) ? t.getLocalizedMessage() : "none"); + out.println(ANSI_RESET); + } + + @Override + public void testAborted(TestDescriptor testDescriptor, Throwable t) { + out.print(ANSI_YELLOW); + out.format("Test aborted: %s\n=> Exception: %s", testDescriptor.toString(), (t != null) ? t.getLocalizedMessage() : "none"); + out.println(ANSI_RESET); + } + + @Override + public void testFailed(TestDescriptor testDescriptor, Throwable t) { + out.print(ANSI_RED); + out.format("Test failed: %s\n=> Exception: %s", testDescriptor.toString(), t.getLocalizedMessage()); + out.println(ANSI_RESET); + } + + @Override + public void testSucceeded(TestDescriptor testDescriptor) { + out.print(ANSI_GREEN); + out.format("Test succeeded: %s", testDescriptor.toString()); + out.println(ANSI_RESET); + } } diff --git a/junit-console/src/main/java/org/junit/gen5/console/Console.java b/junit-console/src/main/java/org/junit/gen5/console/Console.java deleted file mode 100644 index ce34988a341..00000000000 --- a/junit-console/src/main/java/org/junit/gen5/console/Console.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.junit.gen5.console; - -import org.junit.gen5.engine.TestPlan; -import org.junit.gen5.launcher.Launcher; -import org.junit.gen5.launcher.TestExecutionPlan; - -public class Console { - - public static void main(String[] args) throws Throwable { - String className = args[0]; - - // TODO Configure launcher? - Launcher launcher = new Launcher(); - - TestPlan testPlan = TestPlan.builder().classes(Class.forName(className)).build(); - - // TODO Launch parameters: Provide configuration - TestExecutionPlan executionPlan = launcher.discoverTests(testPlan); - - // TODO Register test listener(s) -// .withTestListener(new ColoredPrintingTestListener(System.out)) -// .withTestListener(new TestSummaryReportingTestListener(System.out)) - - // TODO Provide means to allow manipulation of test plan? - launcher.execute(executionPlan); - - } - -} diff --git a/junit-console/src/main/java/org/junit/gen5/console/TestSummaryReportingTestListener.java b/junit-console/src/main/java/org/junit/gen5/console/TestSummaryReportingTestListener.java index 5a1537e614a..635a92ff229 100644 --- a/junit-console/src/main/java/org/junit/gen5/console/TestSummaryReportingTestListener.java +++ b/junit-console/src/main/java/org/junit/gen5/console/TestSummaryReportingTestListener.java @@ -1,66 +1,103 @@ package org.junit.gen5.console; -import java.io.PrintStream; +import org.junit.gen5.engine.TestDescriptor; +import org.junit.gen5.engine.TestListener; -import org.junit.gen5.launcher.TestIdentifier; -import org.junit.gen5.launcher.TestListener; +import java.io.PrintStream; /** * @author Stefan Bechtold * @since 5.0 */ public class TestSummaryReportingTestListener implements TestListener { - private final PrintStream out; - - int testsFound; - int testsSkipped; - int testsAborted; - int testsSucceeded; - int testsFailed; - - private long timeStarted; - private long timePaused; - private long timeFinished; - - public TestSummaryReportingTestListener(PrintStream out) { - this.out = out; - } - - private void reportSummary(String msg) { - timeFinished = System.currentTimeMillis(); - - out.println(String.format( - "%s after %d ms\n" + "[%10d tests found ]\n" + "[%10d tests skipped ]\n" - + "[%10d tests aborted ]\n" + "[%10d tests failed ]\n" + "[%10d tests successful]\n", - msg, timeFinished - timeStarted, testsFound, testsSkipped, testsAborted, testsFailed, testsSucceeded)); - } - - @Override - public void testFound(TestIdentifier testIdentifier) { - testsFound++; - } - - @Override - public void testStarted(TestIdentifier testIdentifier) { - } - - @Override - public void testSkipped(TestIdentifier testIdentifier, Throwable t) { - testsSkipped++; - } - - @Override - public void testAborted(TestIdentifier testIdentifier, Throwable t) { - testsAborted++; - } - - @Override - public void testFailed(TestIdentifier testIdentifier, Throwable t) { - testsFailed++; - } - - @Override - public void testSucceeded(TestIdentifier testIdentifier) { - testsSucceeded++; - } + private final PrintStream out; + + int testsFound; + int testsSkipped; + int testsAborted; + int testsSucceeded; + int testsFailed; + + private long timeStarted; + private long timePaused; + private long timeFinished; + + public TestSummaryReportingTestListener(PrintStream out) { + this.out = out; + } + + @Override + public void testExecutionStarted() { + timeStarted = System.currentTimeMillis(); + } + + @Override + public void testExecutionPaused() { + timePaused = System.currentTimeMillis(); + } + + @Override + public void testExecutionRestarted() { + timeStarted += System.currentTimeMillis() - timePaused; + timePaused = 0; + } + + @Override + public void testExecutionStopped() { + reportSummary("Test run stopped"); + } + + @Override + public void testExecutionFinished() { + reportSummary("Test run finished"); + } + + private void reportSummary(String msg) { + timeFinished = System.currentTimeMillis(); + + out.println(String.format( + "%s after %d ms\n" + + "[%10d tests found ]\n" + + "[%10d tests skipped ]\n" + + "[%10d tests aborted ]\n" + + "[%10d tests failed ]\n" + + "[%10d tests successful]\n", + msg, + timeFinished - timeStarted, + testsFound, + testsSkipped, + testsAborted, + testsFailed, + testsSucceeded + )); + } + + @Override + public void testFound(TestDescriptor testDescriptor) { + testsFound++; + } + + @Override + public void testStarted(TestDescriptor testDescriptor) { + } + + @Override + public void testSkipped(TestDescriptor testDescriptor, Throwable t) { + testsSkipped++; + } + + @Override + public void testAborted(TestDescriptor testDescriptor, Throwable t) { + testsAborted++; + } + + @Override + public void testFailed(TestDescriptor testDescriptor, Throwable t) { + testsFailed++; + } + + @Override + public void testSucceeded(TestDescriptor testDescriptor) { + testsSucceeded++; + } } \ No newline at end of file diff --git a/junit-engine-api/src/main/java/org/junit/gen5/engine/Engine.java b/junit-engine-api/src/main/java/org/junit/gen5/engine/Engine.java deleted file mode 100644 index d3ad31e50cf..00000000000 --- a/junit-engine-api/src/main/java/org/junit/gen5/engine/Engine.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.junit.gen5.engine; - -import java.util.List; - -// TODO Decide on name for Engine -public interface Engine { - - String getId(); - - List discoverTests(TestPlan testPlan); - - void execute(List testDescriptions) throws Throwable; -} diff --git a/junit-engine-api/src/main/java/org/junit/gen5/engine/TestDescriptor.java b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestDescriptor.java index f723c20e28a..fa63c4f80c0 100644 --- a/junit-engine-api/src/main/java/org/junit/gen5/engine/TestDescriptor.java +++ b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestDescriptor.java @@ -1,42 +1,29 @@ - package org.junit.gen5.engine; -import java.util.List; - /** * @author Sam Brannen * @since 5.0 */ public interface TestDescriptor { - - /** - * Get the unique identifier (UID) for the described test. - * - *

Uniqueness must be guaranteed across an entire test plan, - * regardless of how many engines are used behind the scenes. - * - *

The ID is simply the concatenation of the {@linkplain #getEngineId engine ID} - * and the {@linkplain #getTestId test ID} separated by a colon ({@code ":"}) - * — for example, {@code myEngine:test-description-unique-within-my-engine}. - */ - String getId(); - - String getEngineId(); - - String getTestId(); - - String getDisplayName(); - - TestDescriptor getParent(); - - List getChildren(); - - boolean isRoot(); - - boolean isNode(); - - boolean isLeaf(); - - boolean isDynamic(); - -} + /** + * Get the unique identifier (UID) for the described test. + * + *

Uniqueness must be guaranteed across an entire test plan, + * regardless of how many engines are used behind the scenes. + * + *

The ID is simply the concatenation of the {@linkplain #getEngineId engine ID} + * and the {@linkplain #getTestId test ID} separated by a colon ({@code ":"}) + * — for example, {@code myEngine:test-description-unique-within-my-engine}. + */ + default String getUniqueId() { + return String.format("%s:%s", getEngineId(), getTestId()); + }; + + String getEngineId(); + + String getTestId(); + + String getDisplayName(); + + TestDescriptor getParent(); +} \ No newline at end of file diff --git a/junit-engine-api/src/main/java/org/junit/gen5/engine/TestEngine.java b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestEngine.java new file mode 100644 index 00000000000..55eb272421a --- /dev/null +++ b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestEngine.java @@ -0,0 +1,22 @@ +package org.junit.gen5.engine; + +import java.util.Collection; + +public interface TestEngine { + default String getId() { + return getClass().getCanonicalName(); + } + + Collection discoverTests(TestPlanConfiguration configuration); + + default boolean supports(TestDescriptor testDescriptor) { + return testDescriptor.getUniqueId().startsWith(getId()); + } + + default boolean supportsAll(Collection testDescriptors) { + return testDescriptors.stream() + .allMatch(testDescriptor -> supports(testDescriptor)); + } + + void execute(Collection testDescriptions); +} diff --git a/junit-engine-api/src/main/java/org/junit/gen5/engine/TestListener.java b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestListener.java new file mode 100644 index 00000000000..d38ec39f630 --- /dev/null +++ b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestListener.java @@ -0,0 +1,20 @@ +package org.junit.gen5.engine; + +/** + * @author Stefan Bechtold + * @since 5.0 + */ +public interface TestListener { + default void testExecutionStarted() {}; + default void testExecutionPaused() {}; + default void testExecutionRestarted() {}; + default void testExecutionStopped() {}; + default void testExecutionFinished() {}; + + default void testFound(TestDescriptor testDescriptor) {}; + default void testStarted(TestDescriptor testDescriptor) {}; + default void testSkipped(TestDescriptor testDescriptor, Throwable t) {}; + default void testAborted(TestDescriptor testDescriptor, Throwable t) {}; + default void testFailed(TestDescriptor testDescriptor, Throwable t) {}; + default void testSucceeded(TestDescriptor testDescriptor) {}; +} \ No newline at end of file diff --git a/junit-engine-api/src/main/java/org/junit/gen5/engine/TestPlan.java b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestPlan.java deleted file mode 100644 index 2d907988a6f..00000000000 --- a/junit-engine-api/src/main/java/org/junit/gen5/engine/TestPlan.java +++ /dev/null @@ -1,103 +0,0 @@ - -package org.junit.gen5.engine; - -import java.nio.file.Path; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import lombok.Data; - -/** - * @author Sam Brannen - * @author Stefan Bechtold - * @since 5.0 - */ -// TODO make immutable -@Data -public final class TestPlan { - - private Map launchParameters = new HashMap<>(); - private List> classes = new LinkedList<>(); - private List classNames = new LinkedList<>(); - private List packages = new LinkedList<>(); - private List packageNames = new LinkedList<>(); - private List paths = new LinkedList<>(); - private List fileNames = new LinkedList<>(); - private List includePatterns = new LinkedList<>(); - private List excludePatterns = new LinkedList<>(); - - private TestPlan() { - /* no-op */ - } - - public static TestPlanBuilder builder() { - return new TestPlanBuilder(); - } - - public static final class TestPlanBuilder { - - private TestPlan testPlan = new TestPlan(); - - private TestPlanBuilder() { - /* no-op */ - } - - public TestPlanBuilder parameter(String key, String value) { - testPlan.getLaunchParameters().put(key, value); - return this; - } - - public TestPlanBuilder parameters(Map launchParameters) { - testPlan.getLaunchParameters().putAll(launchParameters); - return this; - } - - public TestPlanBuilder classes(Class... classes) { - Arrays.stream(classes).forEach(c -> testPlan.getClasses().add(c)); - return this; - } - - public TestPlanBuilder classNames(String... classNames) { - Arrays.stream(classNames).forEach(n -> testPlan.getClassNames().add(n)); - return this; - } - - public TestPlanBuilder packages(Package... packages) { - Arrays.stream(packages).forEach(p -> testPlan.getPackages().add(p)); - return this; - } - - public TestPlanBuilder packageNames(String... packageNames) { - Arrays.stream(packageNames).forEach(n -> testPlan.getPackageNames().add(n)); - return this; - } - - public TestPlanBuilder paths(Path... paths) { - Arrays.stream(paths).forEach(p -> testPlan.getPaths().add(p)); - return this; - } - - public TestPlanBuilder fileNames(String... fileNames) { - Arrays.stream(fileNames).forEach(n -> testPlan.getFileNames().add(n)); - return this; - } - - public TestPlanBuilder include(String... patterns) { - Arrays.stream(patterns).forEach(p -> testPlan.getIncludePatterns().add(p)); - return this; - } - - public TestPlanBuilder exclude(String... patterns) { - Arrays.stream(patterns).forEach(p -> testPlan.getExcludePatterns().add(p)); - return this; - } - - public TestPlan build() { - return testPlan; - } - } - -} diff --git a/junit-engine-api/src/main/java/org/junit/gen5/engine/TestPlanConfiguration.java b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestPlanConfiguration.java new file mode 100644 index 00000000000..404f655a21c --- /dev/null +++ b/junit-engine-api/src/main/java/org/junit/gen5/engine/TestPlanConfiguration.java @@ -0,0 +1,100 @@ + +package org.junit.gen5.engine; + +import lombok.Value; + +import java.nio.file.Path; +import java.util.*; + +/** + * @author Sam Brannen + * @author Stefan Bechtold + * @since 5.0 + */ +@Value +public final class TestPlanConfiguration { + private Map launchParameters = new HashMap<>(); + private List> classes = new LinkedList<>(); + private List classNames = new LinkedList<>(); + private List packages = new LinkedList<>(); + private List packageNames = new LinkedList<>(); + private List paths = new LinkedList<>(); + private List fileNames = new LinkedList<>(); + private List uniqueIds = new LinkedList<>(); + private List includePatterns = new LinkedList<>(); + private List excludePatterns = new LinkedList<>(); + + private TestPlanConfiguration() { /* no-op */ } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + + private TestPlanConfiguration configuration = new TestPlanConfiguration(); + + private Builder() { + /* no-op */ + } + + public Builder parameter(String key, String value) { + configuration.launchParameters.put(key, value); + return this; + } + + public Builder parameters(Map launchParameters) { + configuration.launchParameters.putAll(launchParameters); + return this; + } + + public Builder classes(Class... classes) { + Arrays.stream(classes).forEach(testClass -> configuration.classes.add(testClass)); + return this; + } + + public Builder classNames(String... classNames) { + Arrays.stream(classNames).forEach(className -> configuration.classNames.add(className)); + return this; + } + + public Builder packages(Package... packages) { + Arrays.stream(packages).forEach(testPackage -> configuration.packages.add(testPackage)); + return this; + } + + public Builder packageNames(String... packageNames) { + Arrays.stream(packageNames).forEach(packageName -> configuration.packageNames.add(packageName)); + return this; + } + + public Builder paths(Path... paths) { + Arrays.stream(paths).forEach(path -> configuration.paths.add(path)); + return this; + } + + public Builder fileNames(String... fileNames) { + Arrays.stream(fileNames).forEach(n -> configuration.fileNames.add(n)); + return this; + } + + public Builder uniqueIds(String... uniqueIds) { + Arrays.stream(uniqueIds).forEach(uniqueId -> configuration.uniqueIds.add(uniqueId)); + return this; + } + + public Builder includePatterns(String... patterns) { + Arrays.stream(patterns).forEach(pattern -> configuration.includePatterns.add(pattern)); + return this; + } + + public Builder excludePatterns(String... patterns) { + Arrays.stream(patterns).forEach(pattern -> configuration.excludePatterns.add(pattern)); + return this; + } + + public TestPlanConfiguration build() { + return configuration; + } + } +} \ No newline at end of file diff --git a/junit-engine-api/src/test/java/org/junit/gen5/engine/TestPlanBuilderTests.java b/junit-engine-api/src/test/java/org/junit/gen5/engine/TestPlanBuilderTests.java deleted file mode 100644 index 16e74004191..00000000000 --- a/junit-engine-api/src/test/java/org/junit/gen5/engine/TestPlanBuilderTests.java +++ /dev/null @@ -1,32 +0,0 @@ - -package org.junit.gen5.engine; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.Test; -import org.junit.gen5.engine.TestPlan.TestPlanBuilder; - -/** - * Unit tests for {@link TestPlanBuilder}. - * - * @author Sam Brannen - * @since 5.0 - */ -public class TestPlanBuilderTests { - - @Test - public void testPlanBuilderDemo() { - TestPlan testPlan = TestPlan.builder() - // TODO support generic configuration - // .configuration(new HashMap(){{ - // put("category", "smoke"); - // }}) - .packageNames("org.example.service.impl").include("*Tests") - // TODO Support engine/test ids or unique ids - // .descriptorIds("junit5:org.example.UserTests#fullname()") - .build(); - - assertThat(testPlan).isNotNull(); - } - -} diff --git a/junit-engine-api/src/test/java/org/junit/gen5/engine/TestPlanConfigurationBuilderTests.java b/junit-engine-api/src/test/java/org/junit/gen5/engine/TestPlanConfigurationBuilderTests.java new file mode 100644 index 00000000000..2ef0f9fa165 --- /dev/null +++ b/junit-engine-api/src/test/java/org/junit/gen5/engine/TestPlanConfigurationBuilderTests.java @@ -0,0 +1,29 @@ +package org.junit.gen5.engine; + +import org.junit.Test; + +import java.util.HashMap; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link TestPlanConfiguration.Builder}. + * + * @author Sam Brannen + * @since 5.0 + */ +public class TestPlanConfigurationBuilderTests { + @Test + public void testPlanBuilderDemo() { + TestPlanConfiguration testPlanConfiguration = TestPlanConfiguration.builder() + .parameters(new HashMap() {{ + put("category", "smoke"); + }}) + .packageNames("org.example.service.impl") + .includePatterns("*Tests") + .uniqueIds("junit5:org.example.UserTests#fullname()") + .build(); + + assertThat(testPlanConfiguration).isNotNull(); + } +} \ No newline at end of file diff --git a/junit-launcher/src/main/java/org/junit/gen5/launcher/Launcher.java b/junit-launcher/src/main/java/org/junit/gen5/launcher/Launcher.java index 592e1cbaaf6..1ddf9cdccf6 100644 --- a/junit-launcher/src/main/java/org/junit/gen5/launcher/Launcher.java +++ b/junit-launcher/src/main/java/org/junit/gen5/launcher/Launcher.java @@ -1,63 +1,34 @@ package org.junit.gen5.launcher; -import java.util.ArrayList; -import java.util.LinkedHashMap; +import org.junit.gen5.engine.TestDescriptor; +import org.junit.gen5.engine.TestEngine; +import org.junit.gen5.engine.TestPlanConfiguration; + import java.util.List; -import java.util.Map; import java.util.ServiceLoader; -import java.util.Set; -import java.util.stream.Collectors; - -import org.junit.gen5.engine.Engine; -import org.junit.gen5.engine.TestDescriptor; -import org.junit.gen5.engine.TestPlan; public class Launcher { - - private final Map> testDescriptionsByEngine = new LinkedHashMap<>(); - - public TestExecutionPlan discoverTests(TestPlan testPlan) { - TestExecutionPlan executionPlan = new TestExecutionPlan(); - for (Engine engine : discoverEngines()) { - executionPlan.addTestIdentifiers(discoverTests(testPlan, engine)); - } - return executionPlan; - } - - private Set discoverTests(TestPlan testPlan, Engine engine) { - List discoveredTests = engine.discoverTests(testPlan); - - Map engineTestDescriptionsByTestId = new LinkedHashMap<>(); - discoveredTests.forEach(testDescription -> engineTestDescriptionsByTestId.put( - new TestIdentifier(engine.getId(), testDescription.getId(), testDescription.getDisplayName()), - testDescription)); - testDescriptionsByEngine.put(engine.getId(), engineTestDescriptionsByTestId); - - return engineTestDescriptionsByTestId.keySet(); - } - - // TODO no exceptions please - public void execute(TestExecutionPlan testPlan) throws Throwable { - for (Engine engine : discoverEngines()) { - Map engineTestDescriptions = testDescriptionsByEngine - .get(engine.getId()); - List testIdentifiers = testPlan.getTestIdentifiers(); - List filtered = engineTestDescriptions.keySet().stream() - .filter(testIdentifier -> testIdentifiers.contains(testIdentifier)).collect(Collectors.toList()); - List testDescriptions = new ArrayList<>(); - for (TestIdentifier testIdentifier : filtered) { - testDescriptions.add(lookup(engine, testIdentifier)); - } - engine.execute(testDescriptions); - } - } - - private TestDescriptor lookup(Engine engine, TestIdentifier testIdentifier) { - return testDescriptionsByEngine.get(engine.getId()).get(testIdentifier); - } - - private Iterable discoverEngines() { - return ServiceLoader.load(Engine.class); - } - -} + private volatile ServiceLoader testEngines; + + public TestPlan createTestPlanWithConfiguration(TestPlanConfiguration configuration) { + TestPlan testPlan = new TestPlan(); + for (TestEngine testEngine : lookupAllTestEngines()) { + testPlan.addTests(testEngine.discoverTests(configuration)); + } + return testPlan; + } + + public void execute(TestPlan testPlan) { + for (TestEngine testEngine : lookupAllTestEngines()) { + List tests = testPlan.getAllTestsForTestEngine(testEngine); + testEngine.execute(tests); + } + } + + private Iterable lookupAllTestEngines() { + if (testEngines == null) { + testEngines = ServiceLoader.load(TestEngine.class); + } + return testEngines; + } +} \ No newline at end of file diff --git a/junit-launcher/src/main/java/org/junit/gen5/launcher/TestExecutionPlan.java b/junit-launcher/src/main/java/org/junit/gen5/launcher/TestExecutionPlan.java deleted file mode 100644 index ab6f2462f41..00000000000 --- a/junit-launcher/src/main/java/org/junit/gen5/launcher/TestExecutionPlan.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.junit.gen5.launcher; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; - -// TODO make immutable? -// TODO name? -public class TestExecutionPlan { - - private final List testIdentifiers = new LinkedList<>(); - - public List getTestIdentifiers() { - return testIdentifiers; - } - - public void addTestIdentifiers(Collection testDescriptions) { - this.testIdentifiers.addAll(testDescriptions); - } - -} diff --git a/junit-launcher/src/main/java/org/junit/gen5/launcher/TestIdentifier.java b/junit-launcher/src/main/java/org/junit/gen5/launcher/TestIdentifier.java deleted file mode 100644 index 93dc9a84a88..00000000000 --- a/junit-launcher/src/main/java/org/junit/gen5/launcher/TestIdentifier.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.junit.gen5.launcher; - -import lombok.Data; - -@Data -public final class TestIdentifier { - - private final String engineId; - private final String testId; - private final String displayName; - -} diff --git a/junit-launcher/src/main/java/org/junit/gen5/launcher/TestListener.java b/junit-launcher/src/main/java/org/junit/gen5/launcher/TestListener.java deleted file mode 100644 index 9f5c607ec5e..00000000000 --- a/junit-launcher/src/main/java/org/junit/gen5/launcher/TestListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.junit.gen5.launcher; - -/** - * @author Stefan Bechtold - * @since 5.0 - */ -// TODO use default methods... -public interface TestListener { - void testFound(TestIdentifier testIdentifier); - void testStarted(TestIdentifier testIdentifier); - void testSkipped(TestIdentifier testIdentifier, Throwable t); - void testAborted(TestIdentifier testIdentifier, Throwable t); - void testFailed(TestIdentifier testIdentifier, Throwable t); - void testSucceeded(TestIdentifier testIdentifier); -} diff --git a/junit-launcher/src/main/java/org/junit/gen5/launcher/TestPlan.java b/junit-launcher/src/main/java/org/junit/gen5/launcher/TestPlan.java new file mode 100644 index 00000000000..cc0e6755410 --- /dev/null +++ b/junit-launcher/src/main/java/org/junit/gen5/launcher/TestPlan.java @@ -0,0 +1,85 @@ +package org.junit.gen5.launcher; + +import org.junit.gen5.engine.TestDescriptor; +import org.junit.gen5.engine.TestEngine; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; + +/** + * @author Sam Brannen + * @since 5.0 + */ +public final class TestPlan { + private static enum State { + NEW, ACTIVE, PAUSED, STOPPED, COMPLETED; + } + private State state = State.NEW; + + private Collection tests = new LinkedList<>(); + TestPlan() { /* no-op */ } + + public boolean isActive() { + return this.state == State.ACTIVE; + } + + public boolean isPaused() { + return this.state == State.PAUSED; + } + + public boolean isStopped() { + return this.state == State.STOPPED; + } + + public boolean isCompleted() { + return this.state == State.COMPLETED; + } + + public void addTest(TestDescriptor testDescriptor) { + addTests(singleton(testDescriptor)); + } + + public void addTests(TestDescriptor... testDescriptors) { + addTests(asList(testDescriptors)); + } + + public void addTests(Collection testDescriptors) { + tests.addAll(testDescriptors); + } + + public Collection getTests() { + return Collections.unmodifiableCollection(tests); + } + + public List getAllTestsForTestEngine(TestEngine testEngine) { + return tests.stream() + .filter(testEngine::supports) + .collect(Collectors.toList()); + } + + public void start() { + System.out.println("Starting test plan"); + this.state = State.ACTIVE; + } + + public void stop() { + System.out.println("Stopping test plan"); + this.state = State.STOPPED; + } + + public void pause() { + System.out.println("Pausing test plan"); + this.state = State.PAUSED; + } + + public void restart() { + System.out.println("Restarting test plan"); + this.state = State.ACTIVE; + } +} \ No newline at end of file diff --git a/junit5-engine/build.gradle b/junit5-engine/build.gradle index 3931d613612..d28856138e6 100644 --- a/junit5-engine/build.gradle +++ b/junit5-engine/build.gradle @@ -1,4 +1,5 @@ dependencies { + compile("org.projectlombok:lombok:${lombokVersion}") compile(project(':junit-engine-api')) compile(project(':junit5-api')) testCompile("junit:junit:4.12") diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JUnit5Engine.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JUnit5Engine.java deleted file mode 100644 index 0bee6a0165b..00000000000 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JUnit5Engine.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.junit.gen5.engine.junit5; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import org.junit.gen5.api.Test; -import org.junit.gen5.engine.Engine; -import org.junit.gen5.engine.TestDescriptor; -import org.junit.gen5.engine.TestPlan; - -public class JUnit5Engine implements Engine { - - private static final String JUNIT5_ENGINE_ID = "junit5"; - - @Override - public String getId() { - return JUNIT5_ENGINE_ID; - } - - @Override - public List discoverTests(TestPlan testPlan) { - return testPlan.getClasses().stream().flatMap(clazz -> Arrays.stream(clazz.getDeclaredMethods())) - // TODO Should be extensible - .filter(method -> method.isAnnotationPresent(Test.class)) - .map(method -> JavaTestDescriptor.fromMethod(method, this)) - // .peek(d -> testPlan.getTestListeners().forEach(l -> - // l.testFound(d))) - .collect(Collectors.toList()); - } - - @Override - public void execute(List testDescriptions) throws Throwable { - for (TestDescriptor testDescription : testDescriptions) { - executeSingleMethod(testDescription); - } - } - - private void executeSingleMethod(TestDescriptor testDescriptor) throws Throwable { - try { - JavaTestDescriptor javaTestDescriptor = (JavaTestDescriptor) testDescriptor; - Object testInstance = instantiateClass(javaTestDescriptor); - invokeMethod(javaTestDescriptor, testInstance); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalArgumentException( - "Test not well-formed and cannot be executed! ID: " + testDescriptor.getId()); - } - } - - private Object instantiateClass(JavaTestDescriptor javaTestDescriptor) - throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { - Class testClass = javaTestDescriptor.getTestClass(); - Constructor constructor = testClass.getDeclaredConstructor(); - if (!constructor.isAccessible()) { - constructor.setAccessible(true); - } - return constructor.newInstance(); - } - - private void invokeMethod(JavaTestDescriptor javaTestDescriptor, Object testInstance) - throws IllegalAccessException, InvocationTargetException { - Method method = javaTestDescriptor.getTestMethod(); - if (!method.isAccessible()) { - method.setAccessible(true); - } - method.invoke(testInstance); - } - -} \ No newline at end of file diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JUnit5TestEngine.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JUnit5TestEngine.java new file mode 100644 index 00000000000..6c5438584d2 --- /dev/null +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JUnit5TestEngine.java @@ -0,0 +1,106 @@ +package org.junit.gen5.engine.junit5; + +import org.junit.gen5.api.Test; +import org.junit.gen5.engine.TestDescriptor; +import org.junit.gen5.engine.TestEngine; +import org.junit.gen5.engine.TestPlanConfiguration; +import org.opentestalliance.AssertionFailedError; +import org.opentestalliance.TestAbortedException; +import org.opentestalliance.TestSkippedException; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.junit.gen5.commons.util.ReflectionUtils.invokeMethod; +import static org.junit.gen5.commons.util.ReflectionUtils.newInstance; + +public class JUnit5TestEngine implements TestEngine { + // TODO - SBE - could be replace by JUnit5TestEngine.class.getCanonicalName(); + private static final String JUNIT5_ENGINE_ID = "junit5"; + + @Override + public String getId() { + return JUNIT5_ENGINE_ID; + } + + @Override + public List discoverTests(TestPlanConfiguration configuration) { + List> testClasses = fetchTestClasses(configuration); + + List testDescriptors = testClasses.stream() + .map(Class::getDeclaredMethods) + .flatMap(Arrays::stream) + .filter(method -> method.isAnnotationPresent(Test.class)) + .map(method -> new JavaTestDescriptor(getId(), method)) + .collect(Collectors.toList()); + + testDescriptors.addAll( + configuration.getUniqueIds().stream() + .map(JavaTestDescriptor::from) + .collect(Collectors.toList()) + ); + + return testDescriptors; + } + + private List> fetchTestClasses(TestPlanConfiguration testPlanConfiguration) { + List> testClasses = new LinkedList<>(); + + // Add specified test classes directly + testClasses.addAll(testPlanConfiguration.getClasses()); + + // Add test classes by name + for (String className : testPlanConfiguration.getClassNames()) { + try { + testClasses.add(Class.forName(className)); + } catch (ClassNotFoundException e) { + String msg = "Could not find test class '%s' in the classpath!"; + throw new IllegalArgumentException(format(msg, className)); + } + } + + // TODO - SBE - Add classes for packages + // TODO - SBE - Add classes for package names + // TODO - SBE - Add classes for paths + // TODO - SBE - Add classes for file names + + return testClasses; + } + + @Override + public boolean supports(TestDescriptor testDescriptor) { + return testDescriptor instanceof JavaTestDescriptor; + } + + @Override + public void execute(Collection testDescriptors) { + for (TestDescriptor testDescriptor : testDescriptors) { + try { + JavaTestDescriptor javaTestDescriptor = (JavaTestDescriptor) testDescriptor; + Object testInstance = newInstance(javaTestDescriptor.getTestClass()); + invokeMethod(javaTestDescriptor.getTestMethod(), testInstance); + System.out.println(String.format("Test %s succeeded!", testDescriptor.getUniqueId())); + } catch (InvocationTargetException e) { + if (e.getTargetException() instanceof TestSkippedException) { + System.out.println(String.format("Test %s skipped!", testDescriptor.getUniqueId())); + } else if (e.getTargetException() instanceof TestAbortedException) { + System.out.println(String.format("Test %s aborted!", testDescriptor.getUniqueId())); + } else if (e.getTargetException() instanceof AssertionFailedError) { + System.out.println(String.format("Test %s failed!", testDescriptor.getUniqueId())); + } else if (e.getTargetException() instanceof RuntimeException) { + throw (RuntimeException) e.getTargetException(); + } else { + throw new RuntimeException(e.getTargetException()); + } + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException( + String.format("Test %s not well-formed and cannot be executed! ", testDescriptor.getUniqueId())); + } + } + } +} \ No newline at end of file diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JavaTestDescriptor.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JavaTestDescriptor.java index 9c5f3315f55..b6d9073c77e 100644 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JavaTestDescriptor.java +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/JavaTestDescriptor.java @@ -1,30 +1,27 @@ package org.junit.gen5.engine.junit5; -import static java.util.Collections.emptyList; -import static java.util.Collections.unmodifiableList; -import static org.junit.gen5.commons.util.ObjectUtils.nullSafeToString; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.junit.gen5.api.Test; +import org.junit.gen5.commons.util.ObjectUtils; +import org.junit.gen5.commons.util.Preconditions; +import org.junit.gen5.engine.TestDescriptor; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.junit.gen5.api.Test; -import org.junit.gen5.commons.util.ObjectUtils; -import org.junit.gen5.commons.util.Preconditions; -import org.junit.gen5.engine.Engine; -import org.junit.gen5.engine.TestDescriptor; - -import lombok.Data; -import lombok.EqualsAndHashCode; +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static org.junit.gen5.commons.util.ObjectUtils.nullSafeToString; /** * {@link TestDescriptor} for tests based on Java classes and methods. * - *

The pattern of the {@link #getTestId test ID} takes the form of + *

The pattern of the {@link #getTestId test ID} takes the form of * {fully qualified class name}#{method name}({comma separated list * of method parameter types}), where each method parameter type is * a fully qualified class name or a primitive type. For example, @@ -40,142 +37,112 @@ @Data @EqualsAndHashCode public class JavaTestDescriptor implements TestDescriptor { - - // The following pattern only supports descriptors for test methods. - // TODO Support descriptors for test classes. - // TODO Decide if we want to support descriptors for packages. - private static final Pattern UID_PATTERN = Pattern.compile("^(.+):(.+)#(.+)\\((.*)\\)$"); - - - private final String id; - - private final String engineId; - - private final String testId; - - private final String displayName; - - private final TestDescriptor parent; - - private final List children; - - private final Class testClass; - - private final Method testMethod; - - private final boolean dynamic; - - - public JavaTestDescriptor(String engineId, Method testMethod) { - this(engineId, null, testMethod, false, null, null); - } - - public JavaTestDescriptor(String engineId, Class testClass, Method testMethod) { - this(engineId, testClass, testMethod, false, null, null); - } - - public JavaTestDescriptor(String engineId, Class testClass, Method testMethod, boolean dynamic, - TestDescriptor parent, List children) { - - Preconditions.notEmpty(engineId, "engineId must not be null or empty"); - if (testMethod == null) { - Preconditions.notNull(testClass, "testClass must not be null"); - } else { - Preconditions.notNull(testMethod, "testMethod must not be null"); - testClass = testMethod.getDeclaringClass(); - } - - this.testClass = testClass; - this.testMethod = testMethod; - this.dynamic = dynamic; - this.displayName = determineDisplayName(testClass, testMethod); - this.parent = parent; - this.children = (children != null ? unmodifiableList(children) : emptyList()); - this.engineId = engineId; - this.testId = createTestId(testClass, testMethod); - this.id = this.engineId + ":" + this.testId; - } - - - @Override - public boolean isRoot() { - return (getParent() == null); - } - - @Override - public boolean isNode() { - return !isLeaf(); - } - - @Override - public boolean isLeaf() { - return getChildren().isEmpty(); - } - - public static JavaTestDescriptor fromMethod(Method testMethod, Engine testEngine) { - return new JavaTestDescriptor(testEngine.getId(), testMethod); - } - - public static JavaTestDescriptor from(final String uid) throws Exception { - Preconditions.notNull(uid, "TestDescriptor UID must not be null"); - - Matcher matcher = UID_PATTERN.matcher(uid); - Preconditions.condition(matcher.matches(), () -> - String.format("Invalid format for %s UID: %s", JavaTestDescriptor.class.getSimpleName(), uid)); - - // TODO Validate contents of matched groups. - String engineId = matcher.group(1); - String className = matcher.group(2); - String methodName = matcher.group(3); - String methodParameters = matcher.group(4); - - Class clazz = loadClass(className); - - System.out.println("DEBUG - method params: " + methodParameters); - - List> paramTypeList = new ArrayList<>(); - for (String type : methodParameters.split(",")) { - type = type.trim(); - if (!type.isEmpty()) { - paramTypeList.add(loadClass(type)); - } - } - - Class[] parameterTypes = paramTypeList.toArray(new Class[paramTypeList.size()]); - Method method = clazz.getDeclaredMethod(methodName, parameterTypes); - - return new JavaTestDescriptor(engineId, clazz, method); - } - - private static Class loadClass(String name) { - try { - // TODO Add support for primitive types and arrays. - return JavaTestDescriptor.class.getClassLoader().loadClass(name); - } - catch (ClassNotFoundException e) { - throw new IllegalStateException("Failed to load class with name '" + name + "'."); - } - } - - private static String createTestId(Class testClass, Method testMethod) { - return (testMethod != null ? String.format("%s#%s(%s)", testClass.getName(), testMethod.getName(), - nullSafeToString(testMethod.getParameterTypes())) : testClass.getName()); - } - - private static String determineDisplayName(Class testClass, Method testMethod) { - if (testMethod != null) { - Test test = testMethod.getAnnotation(Test.class); - if (test != null) { - String customName = test.name(); - if (!ObjectUtils.isEmpty(customName)) { - return customName; - } - } - return testMethod.getName(); - } - else { - return testClass.getSimpleName(); - } - } - -} + // The following pattern only supports descriptors for test methods. + // TODO Support descriptors for test classes. + // TODO Decide if we want to support descriptors for packages. + private static final Pattern UID_PATTERN = Pattern.compile("^(.+):(.+)#(.+)\\((.*)\\)$"); + + public static JavaTestDescriptor from(final String uid) throws RuntimeException { + Preconditions.notNull(uid, "TestDescriptor UID must not be null"); + + Matcher matcher = UID_PATTERN.matcher(uid); + Preconditions.condition(matcher.matches(), () -> + String.format("Invalid format for %s UID: %s", JavaTestDescriptor.class.getSimpleName(), uid)); + + // TODO Validate contents of matched groups. + String engineId = matcher.group(1); + String className = matcher.group(2); + String methodName = matcher.group(3); + String methodParameters = matcher.group(4); + + Class clazz = loadClass(className); + + System.out.println("DEBUG - method params: " + methodParameters); + + List> paramTypeList = new ArrayList<>(); + for (String type : methodParameters.split(",")) { + type = type.trim(); + if (!type.isEmpty()) { + paramTypeList.add(loadClass(type)); + } + } + + Class[] parameterTypes = paramTypeList.toArray(new Class[paramTypeList.size()]); + + try { + Method method = clazz.getDeclaredMethod(methodName, parameterTypes); + return new JavaTestDescriptor(engineId, method); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Failed to get method with name '" + methodName + "'.", e); + } + } + + private final String uniqueId; + private final String engineId; + private final String testId; + private final String displayName; + private final TestDescriptor parent; + private final List children; + private final Class testClass; + + private final Method testMethod; + + public JavaTestDescriptor(String engineId, Method testMethod) { + this(engineId, testMethod.getDeclaringClass(), testMethod, null, null); + } + + public JavaTestDescriptor(String engineId, Class testClass, Method testMethod) { + this(engineId, testClass, testMethod, null, null); + } + + + public JavaTestDescriptor(String engineId, Class testClass, Method testMethod, + TestDescriptor parent, List children) { + + Preconditions.notEmpty(engineId, "engineId must not be null or empty"); + if (testMethod == null) { + Preconditions.notNull(testClass, "testClass must not be null"); + } else { + Preconditions.notNull(testMethod, "testMethod must not be null"); + testClass = testMethod.getDeclaringClass(); + } + + this.testClass = testClass; + this.testMethod = testMethod; + this.displayName = determineDisplayName(testClass, testMethod); + this.parent = parent; + this.children = (children != null ? unmodifiableList(children) : emptyList()); + this.engineId = engineId; + this.testId = createTestId(testClass, testMethod); + this.uniqueId = this.engineId + ":" + this.testId; + } + + private static Class loadClass(String name) { + try { + // TODO Add support for primitive types and arrays. + return JavaTestDescriptor.class.getClassLoader().loadClass(name); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Failed to load class with name '" + name + "'.", e); + } + } + + private static String createTestId(Class testClass, Method testMethod) { + return (testMethod != null ? String.format("%s#%s(%s)", testClass.getName(), testMethod.getName(), + nullSafeToString(testMethod.getParameterTypes())) : testClass.getName()); + } + + private static String determineDisplayName(Class testClass, Method testMethod) { + if (testMethod != null) { + Test test = testMethod.getAnnotation(Test.class); + if (test != null) { + String customName = test.name(); + if (!ObjectUtils.isEmpty(customName)) { + return customName; + } + } + return testMethod.getName(); + } else { + return testClass.getSimpleName(); + } + } +} \ No newline at end of file diff --git a/junit5-engine/src/main/resources/META-INF/services/org.junit.gen5.engine.Engine b/junit5-engine/src/main/resources/META-INF/services/org.junit.gen5.engine.Engine deleted file mode 100644 index 21a61f53937..00000000000 --- a/junit5-engine/src/main/resources/META-INF/services/org.junit.gen5.engine.Engine +++ /dev/null @@ -1 +0,0 @@ -org.junit.gen5.engine.junit5.JUnit5Engine \ No newline at end of file diff --git a/junit5-engine/src/main/resources/META-INF/services/org.junit.gen5.engine.TestEngine b/junit5-engine/src/main/resources/META-INF/services/org.junit.gen5.engine.TestEngine new file mode 100644 index 00000000000..4d8aa05a30e --- /dev/null +++ b/junit5-engine/src/main/resources/META-INF/services/org.junit.gen5.engine.TestEngine @@ -0,0 +1 @@ +org.junit.gen5.engine.junit5.JUnit5TestEngine \ No newline at end of file diff --git a/junit5-engine/src/test/java/org/junit/gen5/engine/junit5/JavaTestDescriptorTests.java b/junit5-engine/src/test/java/org/junit/gen5/engine/junit5/JavaTestDescriptorTests.java index d12bf3a30df..d4abd58166f 100644 --- a/junit5-engine/src/test/java/org/junit/gen5/engine/junit5/JavaTestDescriptorTests.java +++ b/junit5-engine/src/test/java/org/junit/gen5/engine/junit5/JavaTestDescriptorTests.java @@ -34,7 +34,7 @@ public void constructFromMethod() throws Exception { System.out.println("DEBUG - " + descriptor); assertEqual(JUNIT_5_ENGINE_ID, descriptor.getEngineId()); assertEqual(TEST_METHOD_ID, descriptor.getTestId()); - assertEqual(TEST_METHOD_UID, descriptor.getId()); + assertEqual(TEST_METHOD_UID, descriptor.getUniqueId()); assertEqual(getClass(), descriptor.getTestClass()); assertEqual(testMethod, descriptor.getTestMethod()); assertEqual("test", descriptor.getDisplayName(), "display name:"); @@ -60,7 +60,7 @@ public void constructFromMethodWithParameters() throws Exception { System.out.println("DEBUG - " + descriptor); assertEqual(JUNIT_5_ENGINE_ID, descriptor.getEngineId()); assertEqual(TEST_METHOD_STRING_BIGDECIMAL_ID, descriptor.getTestId()); - assertEqual(TEST_METHOD_STRING_BIGDECIMAL_UID, descriptor.getId()); + assertEqual(TEST_METHOD_STRING_BIGDECIMAL_UID, descriptor.getUniqueId()); assertEqual(getClass(), descriptor.getTestClass()); assertEqual(testMethod, descriptor.getTestMethod()); assertEqual("test", descriptor.getDisplayName(), "display name:"); diff --git a/sample-project/build.gradle b/sample-project/build.gradle index 1aa55d761a8..2039421c7bc 100644 --- a/sample-project/build.gradle +++ b/sample-project/build.gradle @@ -1,5 +1,6 @@ dependencies { + testCompile(project(':sample-extension')) + testCompile(project(':junit-launcher')) testCompile(project(':junit5-api')) testRuntime(project(':junit5-engine')) - testCompile(project(':sample-extension')) } diff --git a/sample-project/src/test/java/com/example/Console.java b/sample-project/src/test/java/com/example/Console.java new file mode 100644 index 00000000000..37e4b9cae23 --- /dev/null +++ b/sample-project/src/test/java/com/example/Console.java @@ -0,0 +1,23 @@ +package com.example; + +import org.junit.gen5.engine.TestPlanConfiguration; +import org.junit.gen5.launcher.Launcher; +import org.junit.gen5.launcher.TestPlan; + +public class Console { + public static void main(String[] args) throws Throwable { + // TODO Configure launcher? + Launcher launcher = new Launcher(); + + TestPlanConfiguration testPlanConfiguration = + TestPlanConfiguration.builder() + .classNames(args) + .build(); + + // TODO Launch parameters: Provide configuration + TestPlan testPlan = launcher.createTestPlanWithConfiguration(testPlanConfiguration); + + // TODO Provide means to allow manipulation of test plan? + launcher.execute(testPlan); + } +} \ No newline at end of file