Skip to content

Commit

Permalink
Support nested test style spec (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
uOOOO authored Jun 3, 2024
1 parent 4290671 commit b73ec0f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ android {
dependencies {
implementation("androidx.test:core-ktx:1.5.0")
testImplementation(project(":kotest-extensions-android"))
testImplementation("io.kotest:kotest-runner-junit5:5.8.0")
testImplementation("io.kotest:kotest-runner-junit5:5.9.0")
androidTestImplementation("androidx.test:runner:1.5.2")
androidTestImplementation("androidx.test:core:1.5.0")
androidTestImplementation("androidx.test:rules:1.5.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.os.Build
import androidx.test.core.app.ApplicationProvider
import br.com.colman.kotest.TestApplication
import br.com.colman.kotest.android.extensions.robolectric.RobolectricTest
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
Expand Down Expand Up @@ -65,3 +66,20 @@ abstract class ContainedRobolectricRunnerMergeOverwriteTest : StringSpec({
@Suppress("ClassName")
@RobolectricTest(sdk = Build.VERSION_CODES.O_MR1)
class ContainedRobolectricRunnerMergeOverwriteO_MR1Test : ContainedRobolectricRunnerMergeOverwriteTest()

@RobolectricTest
class ContainedRobolectricRunnerDefaultApplicationBehaviorSpecTest : BehaviorSpec({
Context("Get the Application defined in AndroidManifest.xml") {
Given("A application context") {
val applicationContext = ApplicationProvider.getApplicationContext<Application>()

When("Get class from application context") {
val applicationClass = applicationContext::class

Then("It should be TestApplication") {
applicationClass shouldBe TestApplication::class
}
}
}
}
})
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package br.com.colman.kotest.android.extensions.robolectric

import android.app.Application
import io.kotest.common.runBlocking
import io.kotest.core.extensions.ConstructorExtension
import io.kotest.core.extensions.TestCaseExtension
import io.kotest.core.spec.AutoScan
import io.kotest.core.spec.Spec
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.core.test.isRootTest
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.withContext
import org.robolectric.annotation.Config
import java.util.concurrent.Callable
import org.robolectric.internal.bytecode.Sandbox
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation
import kotlin.time.Duration
import java.util.WeakHashMap
import java.util.concurrent.ExecutorService

/**
* We override TestCaseExtension to configure the Robolectric environment because TestCase intercept
Expand Down Expand Up @@ -110,19 +113,30 @@ class RobolectricExtension : ConstructorExtension, TestCaseExtension {
execute: suspend (TestCase) -> TestResult,
): TestResult {
val containedRobolectricRunner = runnerMap[testCase.spec]!!
// sdkEnvironment.runOnMainThread is important to ensure Robolectric's
// Using sdkEnvironment.executorService to ensure Robolectric's
// looper state doesn't carry over to the next test class.
return containedRobolectricRunner.sdkEnvironment.runOnMainThread(
Callable {
val executorService = containedRobolectricRunner.sdkEnvironment.getExecutorService()
return withContext(executorService.asCoroutineDispatcher()) {
if (testCase.isRootTest()) {
containedRobolectricRunner.containedBefore()
val result = runBlocking { execute(testCase) }
}
val result = execute(testCase)
if (testCase.isRootTest()) {
containedRobolectricRunner.containedAfter()
result
},
)
}
result
}
}
}

private fun Sandbox.getExecutorService(): ExecutorService {
val field = Sandbox::class.java.declaredFields
.firstOrNull { it.type == ExecutorService::class.java }
checkNotNull(field) { "Not found ExecutorService field." }
field.isAccessible = true
return field.get(this) as ExecutorService
}

internal class KotestDefaultApplication : Application()

annotation class RobolectricTest(
Expand Down

0 comments on commit b73ec0f

Please sign in to comment.