Skip to content

Commit 0fbb721

Browse files
authored
Remove robolectric deprecated override (#18)
1 parent b73ec0f commit 0fbb721

File tree

4 files changed

+50
-22
lines changed

4 files changed

+50
-22
lines changed

kotest-extensions-android/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ configurations {
4444
dependencies {
4545
implementation(kotlin("reflect"))
4646
implementation("io.kotest:kotest-framework-api:5.9.0")
47-
implementation("org.robolectric:robolectric:4.11.1")
47+
implementation("org.robolectric:robolectric:4.12.2")
4848
implementation("junit:junit:4.13.2")
4949
implementation("androidx.appcompat:appcompat:1.7.0")
5050

kotest-extensions-android/src/main/kotlin/br/com/colman/kotest/android/extensions/robolectric/ContainedRobolectricRunner.kt

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package br.com.colman.kotest.android.extensions.robolectric
22

3+
import org.junit.experimental.runners.Enclosed
4+
import org.junit.runner.RunWith
35
import org.junit.runners.model.FrameworkMethod
46
import org.robolectric.RobolectricTestRunner
57
import org.robolectric.annotation.Config
68
import org.robolectric.internal.bytecode.InstrumentationConfiguration
79
import org.robolectric.pluginapi.config.ConfigurationStrategy
8-
import org.robolectric.plugins.ConfigConfigurer
10+
import org.robolectric.pluginapi.config.Configurer
11+
import org.robolectric.plugins.HierarchicalConfigurationStrategy
912
import java.lang.reflect.Method
1013

14+
@RunWith(Enclosed::class)
1115
internal class ContainedRobolectricRunner(
12-
private val config: Config?
16+
private val config: Config
1317
) : RobolectricTestRunner(PlaceholderTest::class.java, injector) {
18+
init {
19+
injectKotestConfig()
20+
}
21+
1422
private val placeHolderMethod: FrameworkMethod = children[0]
1523
val sdkEnvironment = getSandbox(placeHolderMethod).also {
1624
configureSandbox(it, placeHolderMethod)
@@ -35,16 +43,14 @@ internal class ContainedRobolectricRunner(
3543
.build()
3644
}
3745

38-
override fun getConfig(method: Method?): Config {
39-
val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java)
40-
.getConfig(testClass.javaClass, method)
41-
42-
if (config != null) {
43-
val configConfigurer = injector.getInstance(ConfigConfigurer::class.java)
44-
return configConfigurer.merge(defaultConfiguration[Config::class.java], config)
45-
}
46-
47-
return super.getConfig(method)
46+
private fun injectKotestConfig() {
47+
val configurationStrategyField =
48+
RobolectricTestRunner::class.java
49+
.getField(ConfigurationStrategy::class.java)
50+
.apply { isAccessible = true }
51+
val configurers = injector.getInstance(arrayOf<Configurer<*>>()::class.java)
52+
val newConfigurationStrategy = KotestHierarchicalConfigurationStrategy(config, configurers)
53+
configurationStrategyField.set(this, newConfigurationStrategy)
4854
}
4955

5056
class PlaceholderTest {
@@ -56,6 +62,19 @@ internal class ContainedRobolectricRunner(
5662
}
5763
}
5864

65+
class KotestHierarchicalConfigurationStrategy(
66+
private val config: Config,
67+
configurers: Array<Configurer<*>>
68+
) : HierarchicalConfigurationStrategy(*configurers) {
69+
override fun getConfig(testClass: Class<*>?, method: Method?): ConfigurationImpl {
70+
val configurationImpl = super.getConfig(testClass, method)
71+
val config = (configurationImpl.get(Config::class.java) as Config)
72+
val newConfig = Config.Builder(config).overlay(this.config).build()
73+
configurationImpl.map()[Config::class.java] = newConfig
74+
return configurationImpl
75+
}
76+
}
77+
5978
companion object {
6079
private val injector = defaultInjector().build()
6180
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package br.com.colman.kotest.android.extensions.robolectric
2+
3+
import java.lang.reflect.Field
4+
import java.lang.reflect.Type
5+
6+
internal fun Class<*>.getField(fieldClass: Type): Field {
7+
return declaredFields.firstOrNull { it.type == fieldClass }
8+
?: throw IllegalStateException("Not found $fieldClass field.")
9+
}
10+
11+
internal inline fun <reified T> Class<*>.getValue(obj: Any): T {
12+
val field = getField(T::class.java)
13+
field.isAccessible = true
14+
return field.get(obj) as T
15+
}

kotest-extensions-android/src/main/kotlin/br/com/colman/kotest/android/extensions/robolectric/RobolectricExtension.kt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ class RobolectricExtension : ConstructorExtension, TestCaseExtension {
115115
val containedRobolectricRunner = runnerMap[testCase.spec]!!
116116
// Using sdkEnvironment.executorService to ensure Robolectric's
117117
// looper state doesn't carry over to the next test class.
118-
val executorService = containedRobolectricRunner.sdkEnvironment.getExecutorService()
118+
val executorService =
119+
Sandbox::class.java
120+
.getValue<ExecutorService>(containedRobolectricRunner.sdkEnvironment)
119121
return withContext(executorService.asCoroutineDispatcher()) {
120122
if (testCase.isRootTest()) {
121123
containedRobolectricRunner.containedBefore()
@@ -129,14 +131,6 @@ class RobolectricExtension : ConstructorExtension, TestCaseExtension {
129131
}
130132
}
131133

132-
private fun Sandbox.getExecutorService(): ExecutorService {
133-
val field = Sandbox::class.java.declaredFields
134-
.firstOrNull { it.type == ExecutorService::class.java }
135-
checkNotNull(field) { "Not found ExecutorService field." }
136-
field.isAccessible = true
137-
return field.get(this) as ExecutorService
138-
}
139-
140134
internal class KotestDefaultApplication : Application()
141135

142136
annotation class RobolectricTest(

0 commit comments

Comments
 (0)