Skip to content

Commit d0f7335

Browse files
committed
Update behavior for custom RunnerBuilder args & adjust tests to new behavior
1 parent 257ce6f commit d0f7335

File tree

4 files changed

+45
-47
lines changed

4 files changed

+45
-47
lines changed

android-junit5-tests/src/test/groovy/de/mannodermaus/gradle/plugins/junit5/PluginSpec.groovy

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -866,26 +866,6 @@ class PluginSpec extends Specification {
866866
project.tasks.findByName("jacocoTestReportRelease") == null
867867
}
868868

869-
def "Instrumentation Test Integration: Doesn't attach RunnerBuilder if disabled"() {
870-
when:
871-
Project project = factory.newProject(rootProject())
872-
.asAndroidApplication()
873-
.applyJunit5Plugin()
874-
.build()
875-
876-
project.android {
877-
testOptions.junitPlatform.instrumentationTests {
878-
enabled false
879-
}
880-
}
881-
882-
project.evaluate()
883-
884-
then:
885-
def args = project.android.defaultConfig.getTestInstrumentationRunnerArguments()
886-
assert !args.containsKey("runnerBuilder")
887-
}
888-
889869
def "Instrumentation Test Integration: Attaches RunnerBuilder"() {
890870
when:
891871
Project project = factory.newProject(rootProject())
@@ -907,7 +887,7 @@ class PluginSpec extends Specification {
907887
assert args["runnerBuilder"].contains("AndroidJUnit5Builder")
908888
}
909889

910-
def "Instrumentation Test Integration: Appends RunnerBuilder if another is already present"() {
890+
def "Instrumentation Test Integration: Raise error if another RunnerBuilder replaces ours"() {
911891
when:
912892
Project project = factory.newProject(rootProject())
913893
.asAndroidApplication()
@@ -927,37 +907,37 @@ class PluginSpec extends Specification {
927907
project.evaluate()
928908

929909
then:
930-
def args = project.android.defaultConfig.getTestInstrumentationRunnerArguments()
931-
assert args.containsKey("runnerBuilder")
932-
933-
// Intentional comma
934-
assert args["runnerBuilder"].contains("com.something.else.OtherRunnerBuilder,")
935-
assert args["runnerBuilder"].contains("AndroidJUnit5Builder")
910+
def expect = thrown(ProjectConfigurationException)
911+
assert expect.cause.message == "Custom runnerBuilder is overwriting JUnit 5 integration! Change your declaration to 'com.something.else.OtherRunnerBuilder,de.mannodermaus.junit5.AndroidJUnit5Builder'."
936912
}
937913

938-
def "Instrumentation Test Integration: Runner Library is not added automatically if disabled"() {
914+
def "Instrumentation Test Integration: Don't raise error if another RunnerBuilder acknowledges ours"() {
939915
when:
940916
Project project = factory.newProject(rootProject())
941917
.asAndroidApplication()
918+
.applyJunit5Plugin()
942919
.build()
943920

944921
project.android {
945-
testOptions.junitPlatform {
946-
instrumentationTests {
947-
enabled false
948-
}
922+
defaultConfig {
923+
testInstrumentationRunnerArgument "runnerBuilder", "com.something.else.OtherRunnerBuilder,de.mannodermaus.junit5.AndroidJUnit5Builder"
924+
}
925+
926+
testOptions.junitPlatform.instrumentationTests {
927+
enabled true
949928
}
950929
}
951930

952931
project.evaluate()
953932

954933
then:
955-
def config = ExtensionsKt.findConfiguration(project.configurations, null,
956-
ConfigurationKind.ANDROID_TEST, ConfigurationScope.RUNTIME_ONLY)
957-
assert config.dependencies.find { it.name == "android-instrumentation-test-runner" } == null
934+
def args = project.android.defaultConfig.getTestInstrumentationRunnerArguments()
935+
assert args.containsKey("runnerBuilder")
936+
assert args["runnerBuilder"].contains("com.something.else.OtherRunnerBuilder")
937+
assert args["runnerBuilder"].contains("de.mannodermaus.junit5.AndroidJUnit5Builder")
958938
}
959939

960-
def "Instrumentation Test Integration: Runner Library is added automatically if enabled"() {
940+
def "Instrumentation Test Integration: Runner Library is added automatically"() {
961941
when:
962942
Project project = factory.newProject(rootProject())
963943
.asAndroidApplication()

android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Plugin.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,15 @@ class AndroidJUnitPlatformPlugin : Plugin<Project> {
128128
}
129129

130130
private fun Project.applyConfigurationParameters() {
131+
// Verify that the JUnit 5 RunnerBuilder wasn't overwritten by user code,
132+
// and if so, throw an exception
133+
val actualRunnerBuilder = android.defaultConfig.testInstrumentationRunnerArguments[RUNNER_BUILDER_ARG]!!
134+
if (!actualRunnerBuilder.contains(JUNIT5_RUNNER_BUILDER_CLASS_NAME)) {
135+
throw IllegalArgumentException(
136+
"Custom runnerBuilder is overwriting JUnit 5 integration! " +
137+
"Change your declaration to '$actualRunnerBuilder,$JUNIT5_RUNNER_BUILDER_CLASS_NAME'.")
138+
}
139+
131140
// Attach runtime-only dependency on JUnit 5 instrumentation test facade
132141
val defaults = loadProperties(VERSIONS_RESOURCE_NAME)
133142
val rtOnly = configurations.findConfiguration(kind = ANDROID_TEST, scope = RUNTIME_ONLY)

instrumentation-runner/src/main/kotlin/de/mannodermaus/junit5/Runner.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package de.mannodermaus.junit5
22

33
import org.junit.platform.runner.JUnitPlatform
4+
import org.junit.runner.Runner
45

56
/**
67
* JUnit Runner implementation using the JUnit Platform as its backbone.
@@ -14,3 +15,8 @@ import org.junit.platform.runner.JUnitPlatform
1415
*/
1516
@Suppress("unused")
1617
internal class AndroidJUnit5(klass: Class<*>) : JUnitPlatform(klass)
18+
19+
/**
20+
* Since we can't reference AndroidJUnit5 directly, use this factory for instantiation.
21+
*/
22+
internal fun createJUnit5Runner(klass: Class<*>): Runner = AndroidJUnit5(klass)

instrumentation-runner/src/main/kotlin/de/mannodermaus/junit5/RunnerBuilder.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,29 @@ private val jupiterTestAnnotations = listOf(
3131
@Suppress("unused")
3232
class AndroidJUnit5Builder : RunnerBuilder() {
3333

34-
@Suppress("UNCHECKED_CAST")
35-
private val runnerClassConstructor by lazy {
36-
// We mustn't explicitly reference junit-platform classes
37-
// because that would enforce a premature minSdkVersion requirement
38-
// on all flavors of a target application.
39-
// Instead, an enabled flavor would provide the dependency automatically
40-
// through the "instrumentation" library artifact.
41-
val klass: Class<Runner> = Class.forName(
42-
"de.mannodermaus.junit5.AndroidJUnit5") as Class<Runner>
43-
klass.getConstructor(Class::class.java)
34+
private val junit5Available by lazy {
35+
try {
36+
Class.forName("org.junit.jupiter.api.Test")
37+
Class.forName("org.junit.jupiter.params.ParameterizedTest")
38+
Class.forName("de.mannodermaus.junit5.AndroidJUnit5")
39+
true
40+
} catch (e: Throwable) {
41+
false
42+
}
4443
}
4544

4645
@Throws(Throwable::class)
4746
override fun runnerForClass(testClass: Class<*>): Runner? {
4847
try {
48+
if (!junit5Available) {
49+
return null
50+
}
51+
4952
if (!testClass.hasJupiterTestMethods()) {
5053
return null
5154
}
5255

53-
return runnerClassConstructor.newInstance(testClass)
56+
return createJUnit5Runner(testClass)
5457

5558
} catch (e: NoClassDefFoundError) {
5659
Log.e(LOG_TAG, "JUnitPlatform not found on runtime classpath")

0 commit comments

Comments
 (0)