为Espresso测试制作CoroutineDispatcher IdlingResource

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (8)

我正试图找到一种方法来很好地实现一个将轮询CoroutineDispatcher isActive属性的IdlingResource 。但是,从调试开始,检查此属性时似乎永远不会有活动作业。

到目前为止,我已经尝试使用AsyncTask THREAD_POOL_EXECUTOR进行内置空闲,但是在使用asCoroutineDispatcher扩展功能并使用它CoroutineDispatcher来启动我的ViewModel 工作时它似乎不起作用。我试过写一个自定义的IdlingResource

视图模型

fun authenticate(username: String, password: String) = viewModelScope.launch(Dispatchers.Default) {
    if (_authenticateRequest.value == true) {
        return@launch
    }

    _authenticateRequest.postValue(true)
    val res = loginRepo.authenticate(username, password)
    _authenticateRequest.postValue(false)

    when {
        res is Result.Success -> {
            _authenticateSuccess.postValue(res.item)
        }
        res is Result.Failure && res.statusCode.isHttpClientError -> {

            _authenticateFailure.postValue(R.string.invalid_password)
        }
        else -> {
            _authenticateFailure.postValue(R.string.network_error)
        }
    }
}

IdlingResource

class CoroutineDispatcherIdlingResource(
    private val resourceName: String,
    private val dispatcher: CoroutineDispatcher
) : IdlingResource {
    private var callback: IdlingResource.ResourceCallback? = null

    override fun getName() = resourceName

    override fun isIdleNow(): Boolean {
        if (dispatcher.isActive) { return false }

        callback?.onTransitionToIdle()
        return true
    }

    override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
        this.callback = callback
    }
}

快速测试

@RunWith(AndroidJUnit4::class)
class LoginIntegrationTest {
    @get:Rule
    val activityRule = ActivityTestRule(MainActivity::class.java)

    var idlingResource: CoroutineDispatcherIdlingResource? = null

    @Before
    fun before() {
        idlingResource = CoroutineDispatcherIdlingResource(this.javaClass.simpleName, Dispatchers.Default)
        IdlingRegistry.getInstance().register(idlingResource)
    }

    @Test
    fun loginFailure() {
        onView(withId(R.id.username))
            .perform(clearText()).perform(typeText("aslkdjqwe"))
        onView(withId(R.id.password))
            .perform(clearText()).perform(typeText("oxicjqwel"))
        onView(withId(R.id.login_button))
            .perform(click())

        onView(withId(com.google.android.material.R.id.snackbar_text))
            .check(matches(withText(R.string.invalid_password)))
    }
}

isActive一旦调用ViewModel'authenticate'函数,我期望该属性为true,但似乎并非如此。它似乎总是错误的,因为CoroutineDispatcher中从未有过活动的Job。

提问于
用户回答回答于

CoroutineContext.isActive是误导性的,因为它检查上下文是否有Job对象以及它是否处于活动状态。A CoroutineDispatcher是一个没有其他元素的上下文,Job因此它总会返回false

为了跟踪延续,您可能需要某种自定义ContinuationInterceptor来跟踪正在进行的和取消的延续。

扫码关注云+社区

领取腾讯云代金券