android - 如何在没有 IdlingResource 的情况下在 Espresso 中等待异步任务
问题描述
我有以下浓缩咖啡代码:
@Test
fun backgroundWorkDisplaysTextAfterLoading() {
onView(withId(R.id.btn_next_fragment)).perform(click())
onView(withId(R.id.btn_background_work)).perform(click())
onView(withId(R.id.hiddenTextView)).check(matches(isDisplayed()))
}
单击 btn_background_work 时,有一个服务调用会在 2 秒内返回响应,然后 hiddenTextview 将变得可见。
如何让 Espresso 等待执行 ViewAssertion ( check(matches(isDisplayed)) ),直到该服务调用返回一个值?服务调用通过 Retrofit 完成,服务调用在 Schedulers.io() 线程上完成。
我无法触及生产代码,因此在生产代码中实现 IdlingResources 是不可能的。
任何帮助表示赞赏!
解决方案
您仍然可以在IdlingResource
不接触生产代码的情况下实施。您只需要创建一个IdlingResource
侦听的回调ViewTreeObserver.OnDrawListener
:
private class ViewPropertyChangeCallback(private val matcher: Matcher<View>, private val view: View) : IdlingResource, ViewTreeObserver.OnDrawListener {
private lateinit var callback: IdlingResource.ResourceCallback
private var matched = false
override fun getName() = "View property change callback"
override fun isIdleNow() = matched
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) {
this.callback = callback
}
override fun onDraw() {
matched = matcher.matches(view)
callback.onTransitionToIdle()
}
}
然后创建一个自定义ViewAction
等待匹配:
fun waitUntil(matcher: Matcher<View>): ViewAction = object : ViewAction {
override fun getConstraints(): Matcher<View> {
return any(View::class.java)
}
override fun getDescription(): String {
return StringDescription().let {
matcher.describeTo(it)
"wait until: $it"
}
}
override fun perform(uiController: UiController, view: View) {
if (!matcher.matches(view)) {
ViewPropertyChangeCallback(matcher, view).run {
try {
IdlingRegistry.getInstance().register(this)
view.viewTreeObserver.addOnDrawListener(this)
uiController.loopMainThreadUntilIdle()
} finally {
view.viewTreeObserver.removeOnDrawListener(this)
IdlingRegistry.getInstance().unregister(this)
}
}
}
}
}
并更新您的测试以使用该操作:
onView(withId(R.id.hiddenTextView)).perform(waitUntil(isDisplayed()))
// or
onView(withId(R.id.hiddenTextView)).perform(waitUntil(withEffectiveVisibility(VISIBLE)))
.check(matches(isDisplayed()))
没有IdlingResource
,Thread.sleep(...)
可能是您的下一个选择,但它会不稳定或效率低下。
推荐阅读
- python - 如何使协议上的“isinstance”还包括函数签名和数据类型?
- javascript - 如何在html和纯javascript中查找元素是否隐藏
- python - 如何只删除括号?(A) 到 A 的 pandas 列中的内容
- javascript - 如何在将数据从一个对象数组映射到另一个对象时使用正则表达式?
- java - Docker & Selenium-Java :- 无法在 docker 容器上运行的 chrome 浏览器中上传图像/文件
- database - CouchDB 的单个数据库中最多可以保存多少个文档?
- php - Laravel - 试图获取非对象的属性'time_in'
- python - Heroku:无法找到软件包 libsm6
- python - 由于列表范围中的第二部分,如何提取元组的第一部分
- java - 用于屏蔽字符串中某些模式的正则表达式