From a8772eaba16fc5edae58d916d7088d33ba8e6690 Mon Sep 17 00:00:00 2001 From: Marcel Schnelle Date: Mon, 6 May 2024 00:44:08 +0900 Subject: [PATCH] Remove need for Jupiter test discovery for API 26+ devices This should pave the road for supporting non-Jupiter test engines for instrumentation tests --- instrumentation/runner/build.gradle.kts | 1 - .../junit5/AndroidJUnit5Builder.kt | 50 ++++++- .../internal/dummy/JupiterTestMethodFinder.kt | 70 ++++++++++ .../extensions/JupiterTestMethodFinder.kt | 124 ------------------ .../junit5/internal/runners/AndroidJUnit5.kt | 37 ++---- .../runners/AndroidJUnit5RunnerParams.kt | 97 +++++++------- .../AndroidLauncherDiscoveryRequest.kt | 13 ++ .../junit5/internal/runners/DummyJUnit5.kt | 22 ++-- .../internal/runners/JUnit5RunnerFactory.kt | 25 +--- .../JupiterTestMethodFinderTests.kt | 12 +- 10 files changed, 212 insertions(+), 239 deletions(-) create mode 100644 instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt delete mode 100644 instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/JupiterTestMethodFinder.kt create mode 100644 instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidLauncherDiscoveryRequest.kt rename instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/{ => dummy}/JupiterTestMethodFinderTests.kt (88%) diff --git a/instrumentation/runner/build.gradle.kts b/instrumentation/runner/build.gradle.kts index 31bbb01a..7b04a0ca 100644 --- a/instrumentation/runner/build.gradle.kts +++ b/instrumentation/runner/build.gradle.kts @@ -100,7 +100,6 @@ dependencies { testImplementation(project(":testutil")) testImplementation(libs.robolectric) - testRuntimeOnly(libs.junitVintageEngine) testRuntimeOnly(libs.junitJupiterEngine) } diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnit5Builder.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnit5Builder.kt index 58b27c89..3b4fcfc6 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnit5Builder.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnit5Builder.kt @@ -2,6 +2,8 @@ package de.mannodermaus.junit5 import android.util.Log import de.mannodermaus.junit5.internal.LOG_TAG +import de.mannodermaus.junit5.internal.LibcoreAccess +import de.mannodermaus.junit5.internal.runners.AndroidJUnit5RunnerParams import de.mannodermaus.junit5.internal.runners.tryCreateJUnit5Runner import org.junit.runner.Runner import org.junit.runners.model.RunnerBuilder @@ -56,11 +58,23 @@ public class AndroidJUnit5Builder : RunnerBuilder() { } } + // One-time parsing setup for runner params, taken from instrumentation arguments + private val params by lazy { + AndroidJUnit5RunnerParams.create().also { params -> + // Apply all environment variables & system properties to the running process + params.registerEnvironmentVariables() + params.registerSystemProperties() + } + } + @Throws(Throwable::class) override fun runnerForClass(testClass: Class<*>): Runner? { + // Ignore a bunch of class in internal packages + if (testClass.isInIgnorablePackage) return null + try { return if (junit5Available) { - tryCreateJUnit5Runner(testClass) + tryCreateJUnit5Runner(testClass) { params } } else { null } @@ -76,4 +90,38 @@ public class AndroidJUnit5Builder : RunnerBuilder() { throw e } } + + /* Private */ + + private val ignorablePackages = setOf( + "java.", + "javax.", + "androidx.", + "com.android.", + "kotlin.", + ) + + private val Class<*>.isInIgnorablePackage: Boolean get() { + return ignorablePackages.any { name.startsWith(it) } + } + + private fun AndroidJUnit5RunnerParams.registerEnvironmentVariables() { + environmentVariables.forEach { (key, value) -> + try { + LibcoreAccess.setenv(key, value) + } catch (t: Throwable) { + Log.w(LOG_TAG, "Error while setting up environment variables.", t) + } + } + } + + private fun AndroidJUnit5RunnerParams.registerSystemProperties() { + systemProperties.forEach { (key, value) -> + try { + System.setProperty(key, value) + } catch (t: Throwable) { + Log.w(LOG_TAG, "Error while setting up system properties.", t) + } + } + } } diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt new file mode 100644 index 00000000..69daac7c --- /dev/null +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt @@ -0,0 +1,70 @@ +package de.mannodermaus.junit5.internal.dummy + +import android.util.Log +import de.mannodermaus.junit5.internal.LOG_TAG +import org.junit.jupiter.api.RepeatedTest +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestFactory +import org.junit.jupiter.api.TestTemplate +import org.junit.jupiter.params.ParameterizedTest +import java.lang.reflect.Method +import java.lang.reflect.Modifier + +/** + * Algorithm to find all methods annotated with a JUnit Jupiter annotation + * for devices running below API level 26 (i.e. those that cannot run Jupiter). + * We're unable to rely on JUnit Platform's own reflection utilities since they rely on Java 8 stuff + */ +internal object JupiterTestMethodFinder { + private val jupiterTestAnnotations = listOf( + Test::class.java, + TestFactory::class.java, + RepeatedTest::class.java, + TestTemplate::class.java, + ParameterizedTest::class.java, + ) + + fun find(cls: Class<*>): Set = cls.doFind(includeInherited = true) + + private fun Class<*>.doFind(includeInherited: Boolean): Set = buildSet { + try { + // Check each method in the Class for the presence + // of the well-known list of JUnit Jupiter annotations. + addAll(declaredMethods.filter(::isApplicableMethod)) + + // Recursively check non-private inner classes as well + declaredClasses.filter(::isApplicableClass).forEach { inner -> + addAll(inner.doFind(includeInherited = false)) + } + + // Attach methods from inherited superclass or (for Java) implemented interfaces, too + if (includeInherited) { + addAll(superclass?.doFind(includeInherited = true).orEmpty()) + interfaces.forEach { i -> addAll(i.doFind(includeInherited = true)) } + } + } catch (t: Throwable) { + Log.w( + LOG_TAG, + "Encountered ${t.javaClass.simpleName} while finding Jupiter test methods for ${this@doFind.name}", + t + ) + } + } + + private fun isApplicableMethod(method: Method): Boolean { + // The method must not be static... + if (Modifier.isStatic(method.modifiers)) return false + + // ...and have at least one of the recognized JUnit 5 annotations + return hasJupiterAnnotation(method) + } + + private fun hasJupiterAnnotation(method: Method): Boolean { + return jupiterTestAnnotations.any { method.getAnnotation(it) != null } + } + + private fun isApplicableClass(cls: Class<*>): Boolean { + // A class must not be private to be considered + return !Modifier.isPrivate(cls.modifiers) + } +} diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/JupiterTestMethodFinder.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/JupiterTestMethodFinder.kt deleted file mode 100644 index 3fa473f1..00000000 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/JupiterTestMethodFinder.kt +++ /dev/null @@ -1,124 +0,0 @@ -package de.mannodermaus.junit5.internal.extensions - -import android.util.Log -import androidx.annotation.RequiresApi -import de.mannodermaus.junit5.internal.LOG_TAG -import org.junit.jupiter.api.RepeatedTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestFactory -import org.junit.jupiter.api.TestTemplate -import org.junit.jupiter.params.ParameterizedTest -import org.junit.platform.commons.support.AnnotationSupport -import org.junit.platform.commons.support.HierarchyTraversalMode -import org.junit.platform.commons.support.ReflectionSupport -import java.lang.reflect.Method -import java.lang.reflect.Modifier -import java.util.stream.Collectors - -internal abstract class JupiterTestMethodFinder { - abstract fun find(cls: Class<*>): Set - abstract fun hasJupiterAnnotation(method: Method): Boolean - - protected val jupiterTestAnnotations = listOf( - Test::class.java, - TestFactory::class.java, - RepeatedTest::class.java, - TestTemplate::class.java, - ParameterizedTest::class.java, - ) - - protected fun isApplicableMethod(method: Method): Boolean { - // The method must not be static... - if (Modifier.isStatic(method.modifiers)) return false - - // ...and have at least one of the recognized JUnit 5 annotations - return hasJupiterAnnotation(method) - } - - protected fun isApplicableClass(cls: Class<*>): Boolean { - // A class must not be private to be considered - return !Modifier.isPrivate(cls.modifiers) - } - - protected fun logError(cls: Class<*>, t: Throwable) { - Log.w( - LOG_TAG, - "Encountered ${t.javaClass.simpleName} while finding Jupiter test methods for ${cls.name}", - t - ) - } -} - -/** - * Algorithm to find all methods annotated with a JUnit Jupiter annotation - * for devices running API level 26 or above. Utilize the reflection utilities - * of the JUnit Platform to ensure consistency with method detection during - * the actual test execution phase - */ -@RequiresApi(26) -internal object JupiterTestMethodFinderApi26 : JupiterTestMethodFinder() { - override fun find(cls: Class<*>): Set { - try { - val candidates = ReflectionSupport - .streamNestedClasses(cls, ::isApplicableClass) - .collect(Collectors.toSet()) - .also { it.add(cls) } - - return buildSet { - candidates.forEach { c -> - addAll( - ReflectionSupport.findMethods( - c, - ::isApplicableMethod, - HierarchyTraversalMode.TOP_DOWN - ) - ) - } - } - } catch (t: Throwable) { - logError(cls, t) - return emptySet() - } - } - - override fun hasJupiterAnnotation(method: Method): Boolean { - return jupiterTestAnnotations.any { annotation -> - AnnotationSupport.isAnnotated(method, annotation) - } - } -} - -/** - * Algorithm to find all methods annotated with a JUnit Jupiter annotation - * for devices running below API level 26 (i.e. those that cannot run Jupiter). - * We're unable to rely on JUnit Platform's own reflection utilities since they rely on Java 8 stuff - */ -internal object JupiterTestMethodFinderLegacy : JupiterTestMethodFinder() { - override fun find(cls: Class<*>): Set = - cls.doFind(includeInherited = true) - - override fun hasJupiterAnnotation(method: Method): Boolean { - return jupiterTestAnnotations.any { method.getAnnotation(it) != null } - } - - private fun Class<*>.doFind(includeInherited: Boolean): Set = buildSet { - try { - // Check each method in the Class for the presence - // of the well-known list of JUnit Jupiter annotations. - addAll(declaredMethods.filter(::isApplicableMethod)) - - // Recursively check non-private inner classes as well - declaredClasses.filter(::isApplicableClass).forEach { inner -> - addAll(inner.doFind(includeInherited = false)) - } - - // Attach methods from inherited superclass or (for Java) implemented interfaces, too - if (includeInherited) { - addAll(superclass?.doFind(includeInherited = true).orEmpty()) - interfaces.forEach { i -> addAll(i.doFind(includeInherited = true)) } - } - } catch (t: Throwable) { - logError(this@doFind, t) - } - } -} diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5.kt index 4685208b..a4713f26 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5.kt @@ -21,20 +21,16 @@ import org.junit.runner.notification.RunNotifier @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) internal class AndroidJUnit5( private val testClass: Class<*>, - private val runnerParams: AndroidJUnit5RunnerParams = createRunnerParams(testClass), + paramsSupplier: () -> AndroidJUnit5RunnerParams = AndroidJUnit5RunnerParams.Companion::create, ) : Runner() { private val launcher = LauncherFactory.create() - private val testTree by lazy { generateTestTree(runnerParams) } + private val testTree by lazy { generateTestTree(paramsSupplier()) } override fun getDescription() = testTree.suiteDescription override fun run(notifier: RunNotifier) { - // Apply all environment variables & system properties to the running process - registerEnvironmentVariables() - registerSystemProperties() - // Finally, launch the test plan on the JUnit Platform launcher.execute( testTree.testPlan, @@ -44,33 +40,16 @@ internal class AndroidJUnit5( /* Private */ - private fun registerEnvironmentVariables() { - runnerParams.environmentVariables.forEach { (key, value) -> - try { - LibcoreAccess.setenv(key, value) - } catch (t: Throwable) { - Log.w(LOG_TAG, "Error while setting up environment variables.", t) - } - } - } + private fun generateTestTree(params: AndroidJUnit5RunnerParams): AndroidJUnitPlatformTestTree { + val request = params.createDiscoveryRequest(testClass) - private fun registerSystemProperties() { - runnerParams.systemProperties.forEach { (key, value) -> - try { - System.setProperty(key, value) - } catch (t: Throwable) { - Log.w(LOG_TAG, "Error while setting up system properties.", t) - } - } - } - - private fun generateTestTree(params: AndroidJUnit5RunnerParams) = - AndroidJUnitPlatformTestTree( - testPlan = launcher.discover(params.createDiscoveryRequest()), + return AndroidJUnitPlatformTestTree( + testPlan = launcher.discover(request), testClass = testClass, - isIsolatedMethodRun = params.isIsolatedMethodRun, + isIsolatedMethodRun = request.isIsolatedMethodRun, isParallelExecutionEnabled = params.isParallelExecutionEnabled, ) + } private fun createNotifier(nextNotifier: RunNotifier) = if (testTree.isParallelExecutionEnabled) { diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5RunnerParams.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5RunnerParams.kt index 2e76cd12..22be0a7b 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5RunnerParams.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnit5RunnerParams.kt @@ -1,76 +1,77 @@ package de.mannodermaus.junit5.internal.runners +import android.os.Bundle import androidx.test.platform.app.InstrumentationRegistry import de.mannodermaus.junit5.internal.discovery.GeneratedFilters import de.mannodermaus.junit5.internal.discovery.ParsedSelectors import de.mannodermaus.junit5.internal.discovery.PropertiesParser import de.mannodermaus.junit5.internal.discovery.ShardingFilter -import org.junit.platform.engine.DiscoverySelector import org.junit.platform.engine.Filter import org.junit.platform.engine.discovery.MethodSelector -import org.junit.platform.launcher.LauncherDiscoveryRequest import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder internal data class AndroidJUnit5RunnerParams( - private val selectors: List = emptyList(), + private val arguments: Bundle = Bundle(), private val filters: List> = emptyList(), val environmentVariables: Map = emptyMap(), val systemProperties: Map = emptyMap(), private val configurationParameters: Map = emptyMap() ) { + fun createDiscoveryRequest(testClass: Class<*>): AndroidLauncherDiscoveryRequest { + val selectors = ParsedSelectors.fromBundle(testClass, arguments) + val isIsolatedMethodRun = selectors.size == 1 && selectors.first() is MethodSelector - fun createDiscoveryRequest(): LauncherDiscoveryRequest = - LauncherDiscoveryRequestBuilder.request() - .selectors(this.selectors) - .filters(*this.filters.toTypedArray()) - .configurationParameters(this.configurationParameters) - .build() - - val isIsolatedMethodRun: Boolean - get() = selectors.size == 1 && selectors.first() is MethodSelector + return AndroidLauncherDiscoveryRequest( + delegate = LauncherDiscoveryRequestBuilder.request() + .selectors(selectors) + .filters(*this.filters.toTypedArray()) + .configurationParameters(this.configurationParameters) + .build(), + isIsolatedMethodRun = isIsolatedMethodRun, + ) + } val isParallelExecutionEnabled: Boolean get() = configurationParameters["junit.jupiter.execution.parallel.enabled"] == "true" -} - -private const val ARG_ENVIRONMENT_VARIABLES = "environmentVariables" -private const val ARG_SYSTEM_PROPERTIES = "systemProperties" -private const val ARG_CONFIGURATION_PARAMETERS = "configurationParameters" -internal fun createRunnerParams(testClass: Class<*>): AndroidJUnit5RunnerParams { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val arguments = InstrumentationRegistry.getArguments() + internal companion object { + fun create(): AndroidJUnit5RunnerParams { + val instrumentation = InstrumentationRegistry.getInstrumentation() + val arguments = InstrumentationRegistry.getArguments() - // Parse environment variables & pass them to the JVM - val environmentVariables = arguments.getString(ARG_ENVIRONMENT_VARIABLES) - ?.run { PropertiesParser.fromString(this) } - ?: emptyMap() + // Parse environment variables & pass them to the JVM + val environmentVariables = arguments.getString(ARG_ENVIRONMENT_VARIABLES) + ?.run { PropertiesParser.fromString(this) } + ?: emptyMap() - // Parse system properties & pass them to the JVM - val systemProperties = arguments.getString(ARG_SYSTEM_PROPERTIES) - ?.run { PropertiesParser.fromString(this) } - ?: emptyMap() + // Parse system properties & pass them to the JVM + val systemProperties = arguments.getString(ARG_SYSTEM_PROPERTIES) + ?.run { PropertiesParser.fromString(this) } + ?: emptyMap() - // Parse configuration parameters - val configurationParameters = arguments.getString(ARG_CONFIGURATION_PARAMETERS) - ?.run { PropertiesParser.fromString(this) } - ?: emptyMap() + // Parse configuration parameters + val configurationParameters = arguments.getString(ARG_CONFIGURATION_PARAMETERS) + ?.run { PropertiesParser.fromString(this) } + ?: emptyMap() - // Parse the selectors to use from what's handed to the runner. - val selectors = ParsedSelectors.fromBundle(testClass, arguments) + // The user may apply test filters to their instrumentation tests through the Gradle plugin's DSL, + // which aren't subject to the filtering imposed through adb. + // A special resource file may be looked up at runtime, containing + // the filters to apply by the AndroidJUnit5 runner. + val filters = GeneratedFilters.fromContext(instrumentation.context) + + listOfNotNull(ShardingFilter.fromArguments(arguments)) - // The user may apply test filters to their instrumentation tests through the Gradle plugin's DSL, - // which aren't subject to the filtering imposed through adb. - // A special resource file may be looked up at runtime, containing - // the filters to apply by the AndroidJUnit5 runner. - val filters = GeneratedFilters.fromContext(instrumentation.context) + - listOfNotNull(ShardingFilter.fromArguments(arguments)) - - return AndroidJUnit5RunnerParams( - selectors, - filters, - environmentVariables, - systemProperties, - configurationParameters - ) + return AndroidJUnit5RunnerParams( + arguments, + filters, + environmentVariables, + systemProperties, + configurationParameters + ) + } + } } + +private const val ARG_ENVIRONMENT_VARIABLES = "environmentVariables" +private const val ARG_SYSTEM_PROPERTIES = "systemProperties" +private const val ARG_CONFIGURATION_PARAMETERS = "configurationParameters" diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidLauncherDiscoveryRequest.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidLauncherDiscoveryRequest.kt new file mode 100644 index 00000000..4b06da2d --- /dev/null +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidLauncherDiscoveryRequest.kt @@ -0,0 +1,13 @@ +package de.mannodermaus.junit5.internal.runners + +import org.junit.platform.launcher.LauncherDiscoveryRequest + +/** + * A special kind of [LauncherDiscoveryRequest] that can also report + * if its discovery is made in the context of an Android "isolated method run" + * (i.e. when only running a single test inside the Android instrumentation). + */ +internal class AndroidLauncherDiscoveryRequest( + delegate: LauncherDiscoveryRequest, + val isIsolatedMethodRun: Boolean, +) : LauncherDiscoveryRequest by delegate diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnit5.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnit5.kt index c0e98d81..bca9548f 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnit5.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnit5.kt @@ -1,7 +1,9 @@ package de.mannodermaus.junit5.internal.runners +import android.os.Build import android.util.Log import de.mannodermaus.junit5.internal.LOG_TAG +import de.mannodermaus.junit5.internal.dummy.JupiterTestMethodFinder import org.junit.runner.Description import org.junit.runner.Runner import org.junit.runner.notification.RunNotifier @@ -11,15 +13,16 @@ import java.lang.reflect.Method * Fake Runner that marks all JUnit 5 methods as ignored, * used for old devices without Java 8 capabilities. */ -internal class DummyJUnit5( - private val testClass: Class<*>, - private val testMethods: Set, -) : Runner() { +internal class DummyJUnit5(private val testClass: Class<*>) : Runner() { + + private val testMethods: Set = JupiterTestMethodFinder.find(testClass) override fun run(notifier: RunNotifier) { Log.w( LOG_TAG, - "JUnit 5 is not supported on this device. All Jupiter tests will be disabled." + "JUnit 5 is not supported on this device: " + + "API level ${Build.VERSION.SDK_INT} is less than 26, the minimum requirement. " + + "All Jupiter tests for ${testClass.name} will be disabled." ) for (testMethod in testMethods) { @@ -28,9 +31,10 @@ internal class DummyJUnit5( } } - override fun getDescription(): Description = Description.createSuiteDescription(testClass).also { - testMethods.forEach { method -> - it.addChild(Description.createTestDescription(testClass, method.name)) + override fun getDescription(): Description = + Description.createSuiteDescription(testClass).also { + testMethods.forEach { method -> + it.addChild(Description.createTestDescription(testClass, method.name)) + } } - } } diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnit5RunnerFactory.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnit5RunnerFactory.kt index ae19570a..4e63c672 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnit5RunnerFactory.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnit5RunnerFactory.kt @@ -1,10 +1,7 @@ package de.mannodermaus.junit5.internal.runners import android.os.Build -import de.mannodermaus.junit5.internal.extensions.JupiterTestMethodFinderApi26 -import de.mannodermaus.junit5.internal.extensions.JupiterTestMethodFinderLegacy import org.junit.runner.Runner -import java.lang.reflect.Method /** * Since we can't reference AndroidJUnit5 directly, use this factory for instantiation. @@ -13,17 +10,14 @@ import java.lang.reflect.Method * Below that however, they wouldn't work; for this case, delegate a dummy runner * which will highlight these tests as ignored. */ -internal fun tryCreateJUnit5Runner(klass: Class<*>): Runner? { - val testMethods = klass.findJupiterTestMethods() - - if (testMethods.isEmpty()) { - return null - } - +internal fun tryCreateJUnit5Runner( + klass: Class<*>, + paramsSupplier: () -> AndroidJUnit5RunnerParams +): Runner? { val runner = if (Build.VERSION.SDK_INT >= 26) { - AndroidJUnit5(klass) + AndroidJUnit5(klass, paramsSupplier) } else { - DummyJUnit5(klass, testMethods) + DummyJUnit5(klass) } // It's still possible for the runner to not be relevant to the test run, @@ -36,10 +30,3 @@ internal fun tryCreateJUnit5Runner(klass: Class<*>): Runner? { private fun Runner.hasExecutableTests() = this.description.children.isNotEmpty() - -private fun Class<*>.findJupiterTestMethods(): Set = - if (Build.VERSION.SDK_INT >= 26) { - JupiterTestMethodFinderApi26.find(this) - } else { - JupiterTestMethodFinderLegacy.find(this) - } diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/JupiterTestMethodFinderTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt similarity index 88% rename from instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/JupiterTestMethodFinderTests.kt rename to instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt index 0337cc98..8df8fe4b 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/JupiterTestMethodFinderTests.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt @@ -1,6 +1,6 @@ @file:Suppress("unused") -package de.mannodermaus.junit5.internal +package de.mannodermaus.junit5.internal.dummy import androidx.annotation.CheckResult import com.google.common.truth.Truth.assertThat @@ -16,9 +16,6 @@ import de.mannodermaus.junit5.HasTaggedTest import de.mannodermaus.junit5.HasTest import de.mannodermaus.junit5.HasTestFactory import de.mannodermaus.junit5.HasTestTemplate -import de.mannodermaus.junit5.internal.extensions.JupiterTestMethodFinder -import de.mannodermaus.junit5.internal.extensions.JupiterTestMethodFinderApi26 -import de.mannodermaus.junit5.internal.extensions.JupiterTestMethodFinderLegacy import de.mannodermaus.junit5.internal.runners.AndroidJUnit5 import de.mannodermaus.junit5.internal.runners.AndroidJUnit5RunnerParams import org.junit.jupiter.api.DynamicContainer.dynamicContainer @@ -27,7 +24,6 @@ import org.junit.jupiter.api.DynamicTest.dynamicTest import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestFactory import org.junit.platform.engine.Filter -import org.junit.platform.engine.discovery.DiscoverySelectors import org.junit.platform.launcher.TagFilter import org.junit.runner.Description import org.junit.runner.notification.RunListener @@ -49,7 +45,7 @@ class JupiterTestMethodFinderTests { HasMultipleInheritancesAndOverrides::class.java to 3, ) - private val allFinders = setOf(JupiterTestMethodFinderLegacy, JupiterTestMethodFinderApi26) + private val allFinders = setOf(JupiterTestMethodFinder) @TestFactory fun `check number of jupiter test methods`() = testForEachFinder { finder -> @@ -104,10 +100,10 @@ class JupiterTestMethodFinderTests { notifier.addListener(listener) val params = AndroidJUnit5RunnerParams( - selectors = listOf(DiscoverySelectors.selectClass(cls)), +// selectors = listOf(DiscoverySelectors.selectClass(cls)), filters = listOfNotNull(filter), ) - AndroidJUnit5(cls, params).run(notifier) + AndroidJUnit5(cls) { params }.run(notifier) return listener }