Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ guidance on upgrading from JUnit 5.x.y to 6.0.0.
[[release-notes-6.0.0-RC2-junit-platform-new-features-and-improvements]]
==== New Features and Improvements

* ❓
* New `selectClasses(...)` and `selectClassesByName(...)` utility methods have been
introduced in `{DiscoverySelectors}` to simplify use cases where one needs to select
multiple individual test classes for the `Launcher` or `EngineTestKit`.


[[release-notes-6.0.0-RC2-junit-jupiter]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

package org.junit.platform.engine.discovery;

import static org.apiguardian.api.API.Status.EXPERIMENTAL;
import static org.apiguardian.api.API.Status.MAINTAINED;
import static org.apiguardian.api.API.Status.STABLE;

Expand Down Expand Up @@ -450,6 +451,119 @@ public static ClassSelector selectClass(@Nullable ClassLoader classLoader, Strin
return new ClassSelector(classLoader, className);
}

/**
* Create a {@code ClassSelector} for each supplied {@link Class}.
*
* @param classes the classes to select; never {@code null} and never containing
* {@code null} class references
* @since 6.0
* @see #selectClass(Class)
* @see #selectClasses(List)
* @see ClassSelector
*/
@API(status = EXPERIMENTAL, since = "6.0")
public static List<ClassSelector> selectClasses(Class<?>... classes) {
return selectClasses(List.of(classes));
}

/**
* Create a {@code ClassSelector} for each supplied {@link Class}.
*
* @param classes the classes to select; never {@code null} and never containing
* {@code null} class references
* @since 6.0
* @see #selectClass(Class)
* @see #selectClasses(Class...)
* @see ClassSelector
*/
@API(status = EXPERIMENTAL, since = "6.0")
public static List<ClassSelector> selectClasses(List<Class<?>> classes) {
Preconditions.notNull(classes, "classes must not be null");
Preconditions.containsNoNullElements(classes, "Individual classes must not be null");

// @formatter:off
return classes.stream()
.distinct()
.map(DiscoverySelectors::selectClass)
.toList();
// @formatter:on
}

/**
* Create a {@code ClassSelector} for each supplied class name.
*
* @param classNames the fully qualified names of the classes to select;
* never {@code null} and never containing {@code null} or blank names
* @since 6.0
* @see #selectClass(String)
* @see #selectClassesByName(List)
* @see #selectClassesByName(ClassLoader, String...)
* @see ClassSelector
*/
@API(status = EXPERIMENTAL, since = "6.0")
public static List<ClassSelector> selectClassesByName(String... classNames) {
return selectClassesByName(List.of(classNames));
}

/**
* Create a {@code ClassSelector} for each supplied class name.
*
* @param classNames the fully qualified names of the classes to select;
* never {@code null} and never containing {@code null} or blank names
* @since 6.0
* @see #selectClass(String)
* @see #selectClassesByName(String...)
* @see #selectClassesByName(ClassLoader, List)
* @see ClassSelector
*/
@API(status = EXPERIMENTAL, since = "6.0")
public static List<ClassSelector> selectClassesByName(List<String> classNames) {
return selectClassesByName(null, classNames);
}

/**
* Create a {@code ClassSelector} for each supplied class name, using the
* supplied class loader.
*
* @param classLoader the class loader to use to load the classes, or {@code null}
* to signal that the default {@code ClassLoader} should be used
* @param classNames the fully qualified names of the classes to select;
* never {@code null} and never containing {@code null} or blank names
* @since 6.0
* @see #selectClass(ClassLoader, String)
* @see #selectClassesByName(ClassLoader, List)
* @see ClassSelector
*/
@API(status = EXPERIMENTAL, since = "6.0")
public static List<ClassSelector> selectClassesByName(@Nullable ClassLoader classLoader, String... classNames) {
return selectClassesByName(classLoader, List.of(classNames));
}

/**
* Create a {@code ClassSelector} for each supplied class name, using the
* supplied class loader.
*
* @param classLoader the class loader to use to load the classes, or {@code null}
* to signal that the default {@code ClassLoader} should be used
* @param classNames the fully qualified names of the classes to select;
* never {@code null} and never containing {@code null} or blank names
* @since 6.0
* @see #selectClass(ClassLoader, String)
* @see ClassSelector
*/
@API(status = EXPERIMENTAL, since = "6.0")
public static List<ClassSelector> selectClassesByName(@Nullable ClassLoader classLoader, List<String> classNames) {
Preconditions.notNull(classNames, "classNames must not be null");
Preconditions.containsNoNullElements(classNames, "Individual class names must not be null");

// @formatter:off
return classNames.stream()
.distinct()
.map(className -> selectClass(classLoader, className))
.toList();
// @formatter:on
}

/**
* Create a {@code MethodSelector} for the supplied <em>fully qualified
* method name</em>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.commons.util.StringUtils;
import org.junit.platform.engine.DiscoverySelector;
import org.junit.platform.engine.discovery.ClassSelector;
import org.junit.platform.engine.discovery.ClasspathResourceSelector;
import org.junit.platform.engine.discovery.DirectorySelector;
import org.junit.platform.engine.discovery.DiscoverySelectors;
Expand Down Expand Up @@ -68,20 +67,6 @@ static List<PackageSelector> selectPackages(String... packageNames) {
// @formatter:on
}

static Stream<ClassSelector> selectClasses(Class<?>... classes) {
Preconditions.notNull(classes, "classes must not be null");
Preconditions.containsNoNullElements(classes, "Individual classes must not be null");

return uniqueStreamOf(classes).map(DiscoverySelectors::selectClass);
}

static Stream<ClassSelector> selectClasses(String... classNames) {
Preconditions.notNull(classNames, "classNames must not be null");
Preconditions.containsNoNullElements(classNames, "Individual class names must not be null");

return uniqueStreamOf(classNames).map(DiscoverySelectors::selectClass);
}

static List<ModuleSelector> selectModules(String... moduleNames) {
Preconditions.notNull(moduleNames, "Module names must not be null");
Preconditions.containsNoNullElements(moduleNames, "Individual module names must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,8 @@ private static Stream<ClassSelector> toClassSelectors(Class<?> suiteClass, Selec
() -> "@SelectClasses on class [%s] must declare at least one class reference or name".formatted(
suiteClass.getName()));
return Stream.concat(//
AdditionalDiscoverySelectors.selectClasses(annotation.value()), //
AdditionalDiscoverySelectors.selectClasses(annotation.names()) //
DiscoverySelectors.selectClasses(annotation.value()).stream(), //
DiscoverySelectors.selectClassesByName(annotation.names()).stream() //
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ private Builder(TestEngine testEngine) {
*
* @param selectors the discovery selectors to add; never {@code null}
* @return this builder for method chaining
* @see #selectors(List)
* @see #filters(Filter...)
* @see #configurationParameter(String, String)
* @see #configurationParameters(Map)
Expand All @@ -339,6 +340,27 @@ public Builder selectors(DiscoverySelector... selectors) {
return this;
}

/**
* Add all of the supplied {@linkplain DiscoverySelector discovery selectors}.
*
* <p>Built-in discovery selectors can be created via the static factory
* methods in {@link org.junit.platform.engine.discovery.DiscoverySelectors}.
*
* @param selectors the discovery selectors to add; never {@code null}
* @return this builder for method chaining
* @since 6.0
* @see #selectors(DiscoverySelector...)
* @see #filters(Filter...)
* @see #configurationParameter(String, String)
* @see #configurationParameters(Map)
* @see #execute()
*/
@API(status = MAINTAINED, since = "6.0")
public Builder selectors(List<? extends DiscoverySelector> selectors) {
this.requestBuilder.selectors(selectors);
return this;
}

/**
* Add all of the supplied {@linkplain Filter filters}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME;
import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses;

import java.util.Collections;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -49,7 +49,7 @@ private Events executeTests(@SuppressWarnings("SameParameterValue") long randomS
.configurationParameter(DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME, ClassOrderer.Random.class.getName())
.configurationParameter(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME, MethodOrderer.Random.class.getName())
.configurationParameter(MethodOrderer.Random.RANDOM_SEED_PROPERTY_NAME, String.valueOf(randomSeed))
.selectors(selectClass(A_TestCase.class), selectClass(B_TestCase.class), selectClass(C_TestCase.class))
.selectors(selectClasses(A_TestCase.class, B_TestCase.class, C_TestCase.class))
.execute()
.testEvents();
// @formatter:on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
import static org.junit.platform.launcher.core.OutputDirectoryProviders.dummyOutputDirectoryProvider;

import java.util.List;
import java.util.function.Consumer;

import org.junit.platform.engine.DiscoveryIssue.Severity;
Expand Down Expand Up @@ -52,6 +53,10 @@ protected EngineExecutionResults executeTestsForClass(Class<?> testClass) {
}

protected EngineExecutionResults executeTests(DiscoverySelector... selectors) {
return executeTests(List.of(selectors));
}

protected EngineExecutionResults executeTests(List<? extends DiscoverySelector> selectors) {
return executeTests(request -> request.selectors(selectors));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses;
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;

import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -44,16 +45,18 @@ void standardTestClassIsCorrectlyDiscovered() {

@Test
void moreThanOneTestClassIsCorrectlyDiscovered() {
LauncherDiscoveryRequest request = request().selectors(selectClass(SecondOfTwoTestCases.class)).build();
LauncherDiscoveryRequest request = //
request().selectors(selectClasses(FirstOfTwoTestCases.class, SecondOfTwoTestCases.class)).build();

TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
assertEquals(1 /*class*/ + 3 /*methods*/, engineDescriptor.getDescendants().size(),
assertEquals(2 /*class*/ + 6 /*methods*/, engineDescriptor.getDescendants().size(),
"# resolved test descriptors");
}

@Test
void moreThanOneTestClassIsExecuted() {
LauncherDiscoveryRequest request = request().selectors(selectClass(FirstOfTwoTestCases.class),
selectClass(SecondOfTwoTestCases.class)).build();
LauncherDiscoveryRequest request = //
request().selectors(selectClasses(FirstOfTwoTestCases.class, SecondOfTwoTestCases.class)).build();

EngineExecutionResults executionResults = executeTests(request);
Events containers = executionResults.containerEvents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement;
import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectNestedClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectNestedMethod;
Expand Down Expand Up @@ -254,8 +255,8 @@ static List<Named<LauncherDiscoveryRequest>> requestsForTestClassWithInvalidTest
.filters(includeClassNamePatterns(
Pattern.quote(InvalidTestCases.InvalidTestMethodTestCase.class.getName()))).build()), //
named("subclasses", defaultRequest() //
.selectors(selectClass(InvalidTestCases.InvalidTestMethodSubclass1TestCase.class),
selectClass(InvalidTestCases.InvalidTestMethodSubclass2TestCase.class)) //
.selectors(selectClasses(InvalidTestCases.InvalidTestMethodSubclass1TestCase.class,
InvalidTestCases.InvalidTestMethodSubclass2TestCase.class)) //
.build()) //
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -93,7 +94,7 @@ void classNameAcrossPackages() {
example.B_TestCase.callSequence = callSequence;

// @formatter:off
executeTests(ClassOrderer.ClassName.class, selectClass(B_TestCase.class), selectClass(example.B_TestCase.class))
executeTests(ClassOrderer.ClassName.class, selectClasses(B_TestCase.class, example.B_TestCase.class))
.assertStatistics(stats -> stats.succeeded(callSequence.size()));
// @formatter:on

Expand Down Expand Up @@ -193,7 +194,7 @@ void classTemplateWithGlobalConfig() {
var classTemplate = ClassTemplateWithLocalConfigTestCase.class;
var otherClass = A_TestCase.class;

executeTests(ClassOrderer.OrderAnnotation.class, selectClass(otherClass), selectClass(classTemplate))//
executeTests(ClassOrderer.OrderAnnotation.class, selectClasses(otherClass, classTemplate))//
.assertStatistics(stats -> stats.succeeded(callSequence.size()));

assertThat(callSequence)//
Expand Down Expand Up @@ -231,11 +232,15 @@ private static void assertIneffectiveOrderAnnotationIssues(List<DiscoveryIssue>
}

private Events executeTests(@Nullable Class<? extends ClassOrderer> classOrderer) {
return executeTests(classOrderer, selectClass(A_TestCase.class), selectClass(B_TestCase.class),
selectClass(C_TestCase.class));
return executeTests(classOrderer, selectClasses(A_TestCase.class, B_TestCase.class, C_TestCase.class));
}

private Events executeTests(@Nullable Class<? extends ClassOrderer> classOrderer, DiscoverySelector... selectors) {
return executeTests(classOrderer, List.of(selectors));
}

private Events executeTests(@Nullable Class<? extends ClassOrderer> classOrderer,
List<? extends DiscoverySelector> selectors) {
// @formatter:off
return testKit(classOrderer, selectors)
.execute()
Expand All @@ -244,17 +249,16 @@ private Events executeTests(@Nullable Class<? extends ClassOrderer> classOrderer
}

private EngineDiscoveryResults discoverTests(@Nullable Class<? extends ClassOrderer> classOrderer) {
return discoverTests(classOrderer, selectClass(A_TestCase.class), selectClass(B_TestCase.class),
selectClass(C_TestCase.class));
return discoverTests(classOrderer, selectClasses(A_TestCase.class, B_TestCase.class, C_TestCase.class));
}

private EngineDiscoveryResults discoverTests(@Nullable Class<? extends ClassOrderer> classOrderer,
DiscoverySelector... selectors) {
List<? extends DiscoverySelector> selectors) {
return testKit(classOrderer, selectors).discover();
}

private static EngineTestKit.Builder testKit(@Nullable Class<? extends ClassOrderer> classOrderer,
DiscoverySelector[] selectors) {
List<? extends DiscoverySelector> selectors) {

var testKit = EngineTestKit.engine("junit-jupiter");
if (classOrderer != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static org.junit.jupiter.api.io.CleanupMode.NEVER;
import static org.junit.jupiter.api.io.CleanupMode.ON_SUCCESS;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod;
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;

Expand Down Expand Up @@ -157,7 +158,7 @@ void cleanupModeOnSuccessFailingField() {

@Test
void cleanupModeOnSuccessFailingThenPassingField() {
executeTests(selectClass(OnSuccessFailingFieldCase.class), selectClass(OnSuccessPassingFieldCase.class));
executeTests(selectClasses(OnSuccessFailingFieldCase.class, OnSuccessPassingFieldCase.class));

assertThat(onSuccessFailingFieldDir).exists();
assertThat(onSuccessPassingFieldDir).doesNotExist();
Expand Down
Loading
Loading