diff --git a/instrumentation/.idea/runConfigurations/Format_Code.xml b/instrumentation/.idea/runConfigurations/Format_Code.xml
new file mode 100644
index 00000000..a99e49f5
--- /dev/null
+++ b/instrumentation/.idea/runConfigurations/Format_Code.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+
+ false
+ false
+
+ false
+ false
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/instrumentation/CHANGELOG.md b/instrumentation/CHANGELOG.md
index 3b65fd95..819895d2 100644
--- a/instrumentation/CHANGELOG.md
+++ b/instrumentation/CHANGELOG.md
@@ -8,6 +8,7 @@ Change Log
- Update to Compose 1.10
- Support instrumentation with JUnit 5 and 6 (the plugin will choose the correct runtime accordingly)
- Avoid error when a client doesn't include junit-jupiter-params on the runtime classpath
+- New: Instead of silently skipping tests when running on unsupported devices, fail test execution via configuration parameter `de.mannodermaus.junit.unsupported.behavior`
## 1.9.0 (2025-10-10)
diff --git a/instrumentation/compose/build.gradle.kts b/instrumentation/compose/build.gradle.kts
index 04a32d7a..e08cb35e 100644
--- a/instrumentation/compose/build.gradle.kts
+++ b/instrumentation/compose/build.gradle.kts
@@ -21,6 +21,10 @@ android {
junitPlatform {
// Using local dependency instead of Maven coordinates
instrumentationTests.enabled = false
+
+ // Fail test execution when running on unsupported device
+ // (TODO: Change this to the proper instrumentationTests API once released as stable)
+ configurationParameter("de.mannodermaus.junit.unsupported.behavior", "fail")
}
dependencies {
diff --git a/instrumentation/core/build.gradle.kts b/instrumentation/core/build.gradle.kts
index bc39abe8..18e87a2e 100644
--- a/instrumentation/core/build.gradle.kts
+++ b/instrumentation/core/build.gradle.kts
@@ -18,6 +18,10 @@ junitPlatform {
// See TaggedTests.kt for usage of this tag
excludeTags("nope")
}
+
+ // Fail test execution when running on unsupported device
+ // (TODO: Change this to the proper instrumentationTests API once released as stable)
+ configurationParameter("de.mannodermaus.junit.unsupported.behavior", "fail")
}
// Use local project dependencies on android-test instrumentation libraries
diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt
index 243c5e42..eae2e022 100644
--- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt
+++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt
@@ -63,7 +63,7 @@ public open class AndroidJUnitFrameworkBuilder internal constructor() : RunnerBu
try {
return if (junitFrameworkAvailable) {
- tryCreateJUnitFrameworkRunner(testClass) { params }
+ tryCreateJUnitFrameworkRunner(testClass, params)
} else {
null
}
diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/ConfigurationParameters.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/ConfigurationParameters.kt
new file mode 100644
index 00000000..1279a030
--- /dev/null
+++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/ConfigurationParameters.kt
@@ -0,0 +1,10 @@
+package de.mannodermaus.junit5.internal
+
+public object ConfigurationParameters {
+ /**
+ * How to behave when executing instrumentation tests on an unsupported device (i.e. too old).
+ * Accepted values: "skip", "fail"
+ */
+ public const val BEHAVIOR_FOR_UNSUPPORTED_DEVICES: String =
+ "de.mannodermaus.junit.unsupported.behavior"
+}
diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt
index f82f8e26..228bdc6c 100644
--- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt
+++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt
@@ -18,10 +18,10 @@ import org.junit.runner.notification.RunNotifier
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
internal class AndroidJUnitFramework(
private val testClass: Class<*>,
- paramsSupplier: () -> JUnitFrameworkRunnerParams = JUnitFrameworkRunnerParams::create,
+ params: JUnitFrameworkRunnerParams,
) : Runner() {
private val launcher = LauncherFactory.create()
- private val testTree by lazy { generateTestTree(paramsSupplier()) }
+ private val testTree by lazy { generateTestTree(params) }
override fun getDescription() = testTree.suiteDescription
diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt
index db7a3706..22bc583f 100644
--- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt
+++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt
@@ -2,10 +2,11 @@ package de.mannodermaus.junit5.internal.runners
import android.os.Build
import android.util.Log
+import de.mannodermaus.junit5.internal.ConfigurationParameters
import de.mannodermaus.junit5.internal.JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION
import de.mannodermaus.junit5.internal.LOG_TAG
import de.mannodermaus.junit5.internal.dummy.JupiterTestMethodFinder
-import java.lang.reflect.Method
+import org.junit.platform.commons.JUnitException
import org.junit.runner.Description
import org.junit.runner.Runner
import org.junit.runner.notification.RunNotifier
@@ -14,22 +15,28 @@ import org.junit.runner.notification.RunNotifier
* Fake Runner that marks all JUnit Framework methods as ignored, used for old devices without the
* required Java capabilities.
*/
-internal class DummyJUnitFramework(private val testClass: Class<*>) : Runner() {
+internal class DummyJUnitFramework(
+ private val testClass: Class<*>,
+ params: JUnitFrameworkRunnerParams,
+) : Runner() {
- private val testMethods: Set = JupiterTestMethodFinder.find(testClass)
+ private val testMethods = JupiterTestMethodFinder.find(testClass)
+ private val behaviorForUnsupportedDevices = params.behaviorForUnsupportedDevices
override fun run(notifier: RunNotifier) {
- Log.w(
- LOG_TAG,
- "JUnit Framework is not supported on this device: " +
- "API level ${Build.VERSION.SDK_INT} is less than " +
- "${JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION}, the minimum requirement. " +
- "All Jupiter tests for ${testClass.name} will be disabled.",
- )
-
- for (testMethod in testMethods) {
- val description = Description.createTestDescription(testClass, testMethod.name)
- notifier.fireTestIgnored(description)
+ when (behaviorForUnsupportedDevices) {
+ "skip" -> skipTests(notifier)
+ "fail" -> failExecution(unsupportedDeviceMessage)
+ else -> {
+ Log.w(
+ LOG_TAG,
+ "Unknown value found for configuration parameter " +
+ "'${ConfigurationParameters.BEHAVIOR_FOR_UNSUPPORTED_DEVICES}': " +
+ "$behaviorForUnsupportedDevices. Apply default behavior " +
+ "and skip tests for this class.",
+ )
+ skipTests(notifier)
+ }
}
}
@@ -39,4 +46,24 @@ internal class DummyJUnitFramework(private val testClass: Class<*>) : Runner() {
it.addChild(Description.createTestDescription(testClass, method.name))
}
}
+
+ private val unsupportedDeviceMessage by lazy {
+ "JUnit Framework is not supported on this device: " +
+ "API level ${Build.VERSION.SDK_INT} is less than " +
+ "${JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION}, the minimum requirement. " +
+ "All Jupiter tests for ${testClass.name} will be disabled."
+ }
+
+ private fun skipTests(notifier: RunNotifier) {
+ Log.w(LOG_TAG, unsupportedDeviceMessage)
+
+ for (testMethod in testMethods) {
+ val description = Description.createTestDescription(testClass, testMethod.name)
+ notifier.fireTestIgnored(description)
+ }
+ }
+
+ private fun failExecution(message: String): Nothing {
+ throw JUnitException(message)
+ }
}
diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt
index 779b0458..5be97c50 100644
--- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt
+++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt
@@ -13,13 +13,13 @@ import org.junit.runner.Runner
*/
internal fun tryCreateJUnitFrameworkRunner(
klass: Class<*>,
- paramsSupplier: () -> JUnitFrameworkRunnerParams,
+ params: JUnitFrameworkRunnerParams,
): Runner? {
val runner =
if (Build.VERSION.SDK_INT >= JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION) {
- AndroidJUnitFramework(klass, paramsSupplier)
+ AndroidJUnitFramework(klass, params)
} else {
- DummyJUnitFramework(klass)
+ DummyJUnitFramework(klass, params)
}
// It's still possible for the runner to not be relevant to the test run,
diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt
index 693634a9..233f157c 100644
--- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt
+++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt
@@ -2,6 +2,7 @@ package de.mannodermaus.junit5.internal.runners
import android.os.Bundle
import androidx.test.platform.app.InstrumentationRegistry
+import de.mannodermaus.junit5.internal.ConfigurationParameters
import de.mannodermaus.junit5.internal.discovery.GeneratedFilters
import de.mannodermaus.junit5.internal.discovery.ParsedSelectors
import de.mannodermaus.junit5.internal.discovery.PropertiesParser
@@ -13,7 +14,7 @@ import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
internal data class JUnitFrameworkRunnerParams(
private val arguments: Bundle = Bundle(),
- private val filters: List> = emptyList(),
+ private val filtersSupplier: () -> List> = { emptyList() },
val environmentVariables: Map = emptyMap(),
val systemProperties: Map = emptyMap(),
private val configurationParameters: Map = emptyMap(),
@@ -25,7 +26,7 @@ internal data class JUnitFrameworkRunnerParams(
fun createDiscoveryRequest(selectors: List): LauncherDiscoveryRequest {
return LauncherDiscoveryRequestBuilder.request()
.selectors(selectors)
- .filters(*this.filters.toTypedArray())
+ .filters(*this.filtersSupplier().toTypedArray())
.configurationParameters(this.configurationParameters)
.build()
}
@@ -33,6 +34,9 @@ internal data class JUnitFrameworkRunnerParams(
val isParallelExecutionEnabled: Boolean
get() = configurationParameters["junit.jupiter.execution.parallel.enabled"] == "true"
+ val behaviorForUnsupportedDevices: String?
+ get() = configurationParameters[ConfigurationParameters.BEHAVIOR_FOR_UNSUPPORTED_DEVICES]
+
val isUsingOrchestrator: Boolean
get() = arguments.getString("orchestratorService") != null
@@ -64,16 +68,19 @@ internal data class JUnitFrameworkRunnerParams(
// 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 =
+ // This requires lazy access because it reaches into JUnit internals,
+ // which may need Java functionality not supported by the current device
+ val filtersSupplier = {
GeneratedFilters.fromContext(instrumentation.context) +
listOfNotNull(ShardingFilter.fromArguments(arguments))
+ }
return JUnitFrameworkRunnerParams(
- arguments,
- filters,
- environmentVariables,
- systemProperties,
- configurationParameters,
+ arguments = arguments,
+ filtersSupplier = filtersSupplier,
+ environmentVariables = environmentVariables,
+ systemProperties = systemProperties,
+ configurationParameters = configurationParameters,
)
}
}
diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt
index 439b19dd..72c9bcbf 100644
--- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt
+++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt
@@ -96,8 +96,8 @@ class JupiterTestMethodFinderTests {
val listener = CountingRunListener()
notifier.addListener(listener)
- val params = JUnitFrameworkRunnerParams(filters = listOfNotNull(filter))
- AndroidJUnitFramework(cls) { params }.run(notifier)
+ val params = JUnitFrameworkRunnerParams(filtersSupplier = { listOfNotNull(filter) })
+ AndroidJUnitFramework(cls, params).run(notifier)
return listener
}
diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt
index f9387287..dd4db452 100644
--- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt
+++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt
@@ -81,7 +81,11 @@ class AndroidJUnitFrameworkTests {
val resultRef = AtomicReference()
val args = buildArgs(shardingConfig)
withMockedInstrumentation(args) {
- val runner = AndroidJUnitFramework(Sample_NormalTests::class.java)
+ val runner =
+ AndroidJUnitFramework(
+ testClass = Sample_NormalTests::class.java,
+ params = JUnitFrameworkRunnerParams(),
+ )
val listener = CollectingRunListener()
val notifier = RunNotifier().also { it.addListener(listener) }
runner.run(notifier)
diff --git a/instrumentation/sample/build.gradle.kts b/instrumentation/sample/build.gradle.kts
index e70be489..761adee1 100644
--- a/instrumentation/sample/build.gradle.kts
+++ b/instrumentation/sample/build.gradle.kts
@@ -40,6 +40,10 @@ junitPlatform {
// Using local dependency instead of Maven coordinates
instrumentationTests.enabled = false
+
+ // Fail test execution when running on unsupported device
+ // (TODO: Change this to the proper instrumentationTests API once released as stable)
+ configurationParameter("de.mannodermaus.junit.unsupported.behavior", "fail")
}
dependencies {
diff --git a/plugin/.idea/runConfigurations/Format_Code.xml b/plugin/.idea/runConfigurations/Format_Code.xml
new file mode 100644
index 00000000..a8e85921
--- /dev/null
+++ b/plugin/.idea/runConfigurations/Format_Code.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/plugin/.idea/runConfigurations/Plugin__Publish_Release_Manually.xml b/plugin/.idea/runConfigurations/Plugin__Publish_Release_Manually.xml
index c56b79ee..9b365bd2 100644
--- a/plugin/.idea/runConfigurations/Plugin__Publish_Release_Manually.xml
+++ b/plugin/.idea/runConfigurations/Plugin__Publish_Release_Manually.xml
@@ -10,16 +10,19 @@
-
-
+
+
true
true
+ false
false
false
+ false
+ false
\ No newline at end of file
diff --git a/plugin/.idea/runConfigurations/Plugin__Update_Public_API_File.xml b/plugin/.idea/runConfigurations/Plugin__Update_Public_API_File.xml
index 26237685..83aff5d7 100644
--- a/plugin/.idea/runConfigurations/Plugin__Update_Public_API_File.xml
+++ b/plugin/.idea/runConfigurations/Plugin__Update_Public_API_File.xml
@@ -4,18 +4,24 @@
-
+
-
+
+
+
true
true
+ false
false
+ false
+ false
+ false
\ No newline at end of file
diff --git a/plugin/CHANGELOG.md b/plugin/CHANGELOG.md
index afe19189..00ae970f 100644
--- a/plugin/CHANGELOG.md
+++ b/plugin/CHANGELOG.md
@@ -4,6 +4,11 @@ Change Log
## Unreleased
- Update to Kotlin 2.3
- Internal: Replace deprecated `OutputDirectoryProvider` with its correct replacement
+- Support instrumentation with JUnit 5 and 6 (the plugin will choose the correct runtime accordingly)
+- Introduce `de.mannodermaus.android-junit-framework` as the new plugin ID
+- New: Control behavior of test execution on unsupported devices via `instrumentationTests.behaviorForUnsupportedDevices`
+ - "Skip": Skip tests and mark them as ignored (default and equal to previous behavior)
+ - "Fail": Throw an exception and fail test execution
## 1.14.0.0 (2025-10-10)
- JUnit 5.14.0
diff --git a/plugin/android-junit5/api/android-junit5.api b/plugin/android-junit5/api/android-junit5.api
index 21bc70bf..2803fae4 100644
--- a/plugin/android-junit5/api/android-junit5.api
+++ b/plugin/android-junit5/api/android-junit5.api
@@ -30,8 +30,8 @@ public abstract class de/mannodermaus/gradle/plugins/junit5/dsl/FiltersExtension
public final fun includeTags ([Ljava/lang/String;)V
}
-public abstract class de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions {
- public fun ()V
+public abstract interface class de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions {
+ public abstract fun getBehaviorForUnsupportedDevices ()Lorg/gradle/api/provider/Property;
public abstract fun getEnabled ()Lorg/gradle/api/provider/Property;
public abstract fun getIncludeExtensions ()Lorg/gradle/api/provider/Property;
public abstract fun getUseConfigurationParameters ()Lorg/gradle/api/provider/Property;
@@ -65,6 +65,14 @@ public abstract class de/mannodermaus/gradle/plugins/junit5/dsl/JacocoOptions$Re
public abstract fun getEnabled ()Lorg/gradle/api/provider/Property;
}
+public final class de/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior : java/lang/Enum {
+ public static final field Fail Lde/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior;
+ public static final field Skip Lde/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior;
+ public static fun getEntries ()Lkotlin/enums/EnumEntries;
+ public static fun valueOf (Ljava/lang/String;)Lde/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior;
+ public static fun values ()[Lde/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior;
+}
+
public abstract class de/mannodermaus/gradle/plugins/junit5/tasks/AndroidJUnit5JacocoReport : org/gradle/testing/jacoco/tasks/JacocoReport {
public fun ()V
}
diff --git a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/AndroidJUnitPlatformExtension.kt b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/AndroidJUnitPlatformExtension.kt
index 924f40ec..56ee424b 100644
--- a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/AndroidJUnitPlatformExtension.kt
+++ b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/AndroidJUnitPlatformExtension.kt
@@ -75,6 +75,7 @@ constructor(project: Project, private val objects: ObjectFactory) : GroovyObject
objects.newInstance(InstrumentationTestOptions::class.java).apply {
enabled.convention(true)
version.convention(Libraries.Instrumentation.version)
+ behaviorForUnsupportedDevices.convention(UnsupportedDeviceBehavior.Skip)
includeExtensions.convention(false)
useConfigurationParameters.convention(true)
}
diff --git a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions.kt b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions.kt
index fd56dc84..973575de 100644
--- a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions.kt
+++ b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions.kt
@@ -4,26 +4,31 @@ import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
/** Options for controlling instrumentation test execution */
-public abstract class InstrumentationTestOptions {
+public interface InstrumentationTestOptions {
/**
* Whether to configure JUnit 5 instrumentation tests automatically when junit-jupiter-api is
* added as an androidTestImplementation dependency.
*/
- @get:Input public abstract val enabled: Property
+ @get:Input public val enabled: Property
/** The version of the instrumentation libraries to autoconfigure. */
- @get:Input public abstract val version: Property
+ @get:Input public val version: Property
+
+ /**
+ * How to behave when executing instrumentation tests on an unsupported device (i.e. too old).
+ */
+ @get:Input public val behaviorForUnsupportedDevices: Property
/**
* Whether to include a dependency on the android-test-extensions library on top of the main
* instrumentation artifacts.
*/
- @get:Input public abstract val includeExtensions: Property
+ @get:Input public val includeExtensions: Property
/**
* Whether to use configuration parameters configured via the plugin DSL for instrumentation
* tests, too.
*/
- @get:Input public abstract val useConfigurationParameters: Property
+ @get:Input public val useConfigurationParameters: Property
}
diff --git a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior.kt b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior.kt
new file mode 100644
index 00000000..de5118f1
--- /dev/null
+++ b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/UnsupportedDeviceBehavior.kt
@@ -0,0 +1,11 @@
+package de.mannodermaus.gradle.plugins.junit5.dsl
+
+/**
+ * How to react when instrumentation tests are executed on a device that doesn't meet the minSdk
+ * requirement imposed by the JUnit Framework instrumentation libraries. By default, these tests are
+ * silently skipped; set it to [Fail] to raise an error and abort test execution instead.
+ */
+public enum class UnsupportedDeviceBehavior(internal val value: String) {
+ Skip("skip"),
+ Fail("fail"),
+}
diff --git a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configure.kt b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configure.kt
index ec9ffefc..4ef352fc 100644
--- a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configure.kt
+++ b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configure.kt
@@ -22,6 +22,9 @@ import de.mannodermaus.gradle.plugins.junit5.internal.extensions.usesJUnitJupite
import de.mannodermaus.gradle.plugins.junit5.internal.usage.DependencyUsageDetector
import de.mannodermaus.gradle.plugins.junit5.tasks.AndroidJUnit5JacocoReport
import de.mannodermaus.gradle.plugins.junit5.tasks.AndroidJUnit5WriteFilters
+import kotlin.collections.component1
+import kotlin.collections.component2
+import kotlin.collections.forEach
import org.gradle.api.Project
import org.gradle.api.tasks.testing.Test
@@ -125,18 +128,28 @@ private fun AndroidJUnitPlatformExtension.prepareInstrumentationTests(
// Copy over configuration parameters to instrumentation tests
if (instrumentationTests.useConfigurationParameters.get()) {
- val instrumentationParams = runnerArgs.getAsList("configurationParameters").toMutableList()
-
- this.configurationParameters.get().forEach { (key, value) ->
- instrumentationParams.add("$key=$value")
- }
-
- runnerArgs["configurationParameters"] = instrumentationParams.joinToString(",")
+ runnerArgs.addConfigurationParameters(this.configurationParameters.get())
}
+ // Supply behavior value for unsupported devices (i.e. how to react when running on old devices)
+ runnerArgs.addConfigurationParameter(
+ "de.mannodermaus.junit.unsupported.behavior",
+ instrumentationTests.behaviorForUnsupportedDevices.get().value,
+ )
+
attachDependencies(project, "androidTestImplementation")
}
+private fun MutableMap.addConfigurationParameters(values: Map) {
+ val instrumentationParams = this.getAsList("configurationParameters").toMutableList()
+ values.forEach { (key, value) -> instrumentationParams.add("$key=$value") }
+ this["configurationParameters"] = instrumentationParams.joinToString(",")
+}
+
+private fun MutableMap.addConfigurationParameter(key: String, value: String) {
+ addConfigurationParameters(mapOf(key to value))
+}
+
/**
* Construct an artifact ID (i.e. `de.mannodermaus:hoge:1.2.3`) compatible with the given supported
* JUnit version. Depending on the JUnit version, the artifact ID may include a version-specific
diff --git a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/InstrumentationSupportTests.kt b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/InstrumentationSupportTests.kt
index 9ef44084..55c36c7b 100644
--- a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/InstrumentationSupportTests.kt
+++ b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/InstrumentationSupportTests.kt
@@ -4,6 +4,7 @@ import com.google.common.truth.Truth.assertThat
import de.mannodermaus.Libraries.Instrumentation
import de.mannodermaus.Libraries.JUnit
import de.mannodermaus.Libraries.JUnit.JUnit5
+import de.mannodermaus.gradle.plugins.junit5.dsl.UnsupportedDeviceBehavior
import de.mannodermaus.gradle.plugins.junit5.extensions.android
import de.mannodermaus.gradle.plugins.junit5.internal.artifact
import de.mannodermaus.gradle.plugins.junit5.internal.config.ANDROID_JUNIT5_RUNNER_BUILDER_CLASS
@@ -79,6 +80,31 @@ internal class InstrumentationSupportTests {
/* Configuration parameters */
+ @Test
+ fun `always includes config param for unsupported device behavior`() {
+ project.addJUnit(JUnit5, "androidTest")
+ project.evaluate()
+
+ val runnerArgs =
+ project.android.defaultConfig.testInstrumentationRunnerArguments[
+ "configurationParameters"]
+ assertThat(runnerArgs).contains("de.mannodermaus.junit.unsupported.behavior=skip")
+ }
+
+ @Test
+ fun `can configure the unsupported device behavior via dsl`() {
+ project.addJUnit(JUnit5, "androidTest")
+ project.junitPlatform.instrumentationTests.behaviorForUnsupportedDevices.set(
+ UnsupportedDeviceBehavior.Fail
+ )
+ project.evaluate()
+
+ val runnerArgs =
+ project.android.defaultConfig.testInstrumentationRunnerArguments[
+ "configurationParameters"]
+ assertThat(runnerArgs).contains("de.mannodermaus.junit.unsupported.behavior=fail")
+ }
+
@Test
fun `copy configuration parameters to test runner arguments`() {
project.addJUnit(JUnit5, "androidTest")
@@ -88,11 +114,11 @@ internal class InstrumentationSupportTests {
}
project.evaluate()
- assertThat(
- project.android.defaultConfig.testInstrumentationRunnerArguments[
- "configurationParameters"]
- )
- .isEqualTo("my.parameter1=true,my.parameter2=1234")
+ val runnerArgs =
+ project.android.defaultConfig.testInstrumentationRunnerArguments[
+ "configurationParameters"]
+ assertThat(runnerArgs).contains("my.parameter1=true")
+ assertThat(runnerArgs).contains("my.parameter2=1234")
}
@Test
@@ -105,11 +131,11 @@ internal class InstrumentationSupportTests {
}
project.evaluate()
- assertThat(
- project.android.defaultConfig.testInstrumentationRunnerArguments[
- "configurationParameters"]
- )
- .isNull()
+ val runnerArgs =
+ project.android.defaultConfig.testInstrumentationRunnerArguments[
+ "configurationParameters"]
+ assertThat(runnerArgs).doesNotContain("my.parameter1=true")
+ assertThat(runnerArgs).doesNotContain("my.parameter2=1234")
}
/* Dependencies */