Skip to content

Instantly share code, notes, and snippets.

@tomkoptel
Last active April 18, 2018 06:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomkoptel/1101b2bb61f3daf251e3d627ee533b92 to your computer and use it in GitHub Desktop.
Save tomkoptel/1101b2bb61f3daf251e3d627ee533b92 to your computer and use it in GitHub Desktop.
JUnit 4 TestRule that replaces CoroutinesProvider implementation with Espresso aware one.
import android.support.test.espresso.IdlingRegistry
import android.support.test.espresso.IdlingResource
import kotlinx.coroutines.experimental.CoroutineScope
import kotlinx.coroutines.experimental.CoroutineStart
import kotlinx.coroutines.experimental.Job
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import kotlin.coroutines.experimental.CoroutineContext
// We use Kotlin alias to not confuse original high-order function with our delegate
import kotlinx.coroutines.experimental.launch as coroutineLaunch
// https://gist.github.com/tomkoptel/6563da1e3c7426d36596ed84e354f5d7
import com.sample.utils.CoroutinesProvider
/**
* Following [TestRule] ensures that Espresso waits for the underlying coroutines to finish their execution. We
* perform the fit by overriding Singleton component that serves as simplified DI implementation in the project.
*/
class CoroutinesIdlingResourceRule : TestRule {
private val resources = mutableListOf<IdlingResource>()
private val idlingRegistry = IdlingRegistry.getInstance()
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
overrideDefaultCoroutinesProvider()
base.evaluate()
resources.forEach { idlingRegistry.unregister(it) }
}
}
}
private fun overrideDefaultCoroutinesProvider() {
// This is a dummy way to override the dependency. I have used custom Application class to cache global singleton component
// that is used as an access point to replace dependency with custom implementation.
AppUnderTest.component().coroutinesProvider = object : CoroutinesProvider {
override fun launch(
context: CoroutineContext,
start: CoroutineStart,
parent: Job?,
block: suspend CoroutineScope.() -> Unit
): Job {
// Use original couroutoine factory function. 'coroutineLaunch' is an alias of original `launch`
val job = coroutineLaunch(context, start, parent, block)
// Tranform job to IdlingResource and register in the Espresso
job.asIdlingResource().let {
idlingRegistry.register(it)
resources.add(it)
}
return job
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment