how do you get an Idlingresource to work in Kotlin with coroutines

Viewed 2528

My Espresso Idling Resource is not working - it compiles and runs but no longer waits long enough for the result to be returned from the 'net.


  1. Start with https://github.com/chiuki/espresso-samples/tree/master/idling-resource-okhttp
  2. Convert the main activity to Kotlin - test (which is still in java) still works with OKHttpIdlingResource
  3. Convert to anko coroutine call instead of retrofit.enqueue - test no longer works.

Here is the new code for MainActivity in its entirety

import android.app.Activity
import android.os.Bundle
import android.widget.TextView
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import org.jetbrains.anko.coroutines.experimental.bg

import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory

class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        doCallAsync()
    }

    private fun doCallAsync() = async(UI) {

        val user = bg { getUser() }
        val name = user.await().name
        val nameView = findViewById(R.id.name) as TextView

        nameView.text = name;

    }

    private fun getUser(): User {

        val retrofit = Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(MoshiConverterFactory.create())
                .client(OkHttpProvider.getOkHttpInstance())
                .build()

        val service = retrofit.create(GitHubService::class.java)


        val response = service.getUser("chiuki").execute().body()

        return response!!

    }
}

2 Answers

You have to create an IdlingResource to tell Espresso whether the app is currently idle or not (as Kiskae wrote). AFAIK for coroutines there does not exist a central registry that can tell you whether there is a coroutine running.

So you have to keep track of them yourself as suggested in the documentation by using a CountingIdlingResource. Add this convenience async-wrapper to your project:

public fun <T> asyncRes(
        idlingResource: CountingIdlingResource,
        context: CoroutineContext = DefaultDispatcher,
        start: CoroutineStart = CoroutineStart.DEFAULT,
        parent: Job? = null,
        block: suspend CoroutineScope.() -> T
): Deferred<T> = async(context, start, parent) {
    try {
        idlingResource.increment()
        block()
    } finally {
        idlingResource.decrement()
    }
}

Add an instance of CountingIdlingResource inside your Activity, call asyncRes instead of async and pass in the CountingIdlingResource.

class MainActivity : Activity() {

    // Active coroutine counter
    val idlingResource = CountingIdlingResource("coroutines")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        doCallAsync()
    }

    private fun doCallAsync() = asyncRes(idlingResource, UI) {
        ...
    }
    ...
}
Related