Skip to content

Commit b73ec0f

Browse files
authored
Support nested test style spec (#13)
1 parent 4290671 commit b73ec0f

File tree

3 files changed

+42
-10
lines changed

3 files changed

+42
-10
lines changed

kotest-extensions-android/kotest-extensions-android-tests/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ android {
3939
dependencies {
4040
implementation("androidx.test:core-ktx:1.5.0")
4141
testImplementation(project(":kotest-extensions-android"))
42-
testImplementation("io.kotest:kotest-runner-junit5:5.8.0")
42+
testImplementation("io.kotest:kotest-runner-junit5:5.9.0")
4343
androidTestImplementation("androidx.test:runner:1.5.2")
4444
androidTestImplementation("androidx.test:core:1.5.0")
4545
androidTestImplementation("androidx.test:rules:1.5.0")

kotest-extensions-android/kotest-extensions-android-tests/src/test/kotlin/br/com/colman/kotest/android/extensions/ContainedRobolectricTest.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.os.Build
55
import androidx.test.core.app.ApplicationProvider
66
import br.com.colman.kotest.TestApplication
77
import br.com.colman.kotest.android.extensions.robolectric.RobolectricTest
8+
import io.kotest.core.spec.style.BehaviorSpec
89
import io.kotest.core.spec.style.StringSpec
910
import io.kotest.matchers.shouldBe
1011
import io.kotest.matchers.shouldNotBe
@@ -65,3 +66,20 @@ abstract class ContainedRobolectricRunnerMergeOverwriteTest : StringSpec({
6566
@Suppress("ClassName")
6667
@RobolectricTest(sdk = Build.VERSION_CODES.O_MR1)
6768
class ContainedRobolectricRunnerMergeOverwriteO_MR1Test : ContainedRobolectricRunnerMergeOverwriteTest()
69+
70+
@RobolectricTest
71+
class ContainedRobolectricRunnerDefaultApplicationBehaviorSpecTest : BehaviorSpec({
72+
Context("Get the Application defined in AndroidManifest.xml") {
73+
Given("A application context") {
74+
val applicationContext = ApplicationProvider.getApplicationContext<Application>()
75+
76+
When("Get class from application context") {
77+
val applicationClass = applicationContext::class
78+
79+
Then("It should be TestApplication") {
80+
applicationClass shouldBe TestApplication::class
81+
}
82+
}
83+
}
84+
}
85+
})

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
package br.com.colman.kotest.android.extensions.robolectric
22

33
import android.app.Application
4-
import io.kotest.common.runBlocking
54
import io.kotest.core.extensions.ConstructorExtension
65
import io.kotest.core.extensions.TestCaseExtension
76
import io.kotest.core.spec.AutoScan
87
import io.kotest.core.spec.Spec
98
import io.kotest.core.test.TestCase
109
import io.kotest.core.test.TestResult
10+
import io.kotest.core.test.isRootTest
11+
import kotlinx.coroutines.asCoroutineDispatcher
12+
import kotlinx.coroutines.withContext
1113
import org.robolectric.annotation.Config
12-
import java.util.concurrent.Callable
14+
import org.robolectric.internal.bytecode.Sandbox
1315
import kotlin.reflect.KClass
1416
import kotlin.reflect.full.findAnnotation
1517
import kotlin.time.Duration
1618
import java.util.WeakHashMap
19+
import java.util.concurrent.ExecutorService
1720

1821
/**
1922
* We override TestCaseExtension to configure the Robolectric environment because TestCase intercept
@@ -110,19 +113,30 @@ class RobolectricExtension : ConstructorExtension, TestCaseExtension {
110113
execute: suspend (TestCase) -> TestResult,
111114
): TestResult {
112115
val containedRobolectricRunner = runnerMap[testCase.spec]!!
113-
// sdkEnvironment.runOnMainThread is important to ensure Robolectric's
116+
// Using sdkEnvironment.executorService to ensure Robolectric's
114117
// looper state doesn't carry over to the next test class.
115-
return containedRobolectricRunner.sdkEnvironment.runOnMainThread(
116-
Callable {
118+
val executorService = containedRobolectricRunner.sdkEnvironment.getExecutorService()
119+
return withContext(executorService.asCoroutineDispatcher()) {
120+
if (testCase.isRootTest()) {
117121
containedRobolectricRunner.containedBefore()
118-
val result = runBlocking { execute(testCase) }
122+
}
123+
val result = execute(testCase)
124+
if (testCase.isRootTest()) {
119125
containedRobolectricRunner.containedAfter()
120-
result
121-
},
122-
)
126+
}
127+
result
128+
}
123129
}
124130
}
125131

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+
126140
internal class KotestDefaultApplication : Application()
127141

128142
annotation class RobolectricTest(

0 commit comments

Comments
 (0)