android - Android Espresso UI 测试 - 使用 Idling 资源等待屏幕上的元素
问题描述
Android
我开始使用Espresso
框架为应用程序编写 UI 测试。我面临一个问题,测试通常会失败,因为检查屏幕上是否存在某些元素是在显示该元素之前发生的。在我的情况下 - 如果我运行我的测试 10 次 - 3-4 次它会失败,因为它不会在屏幕上找到一个元素
我知道Google
建议使用这样的东西idling resources
。但他们也建议以修改应用程序代码的方式使用它——这是一个糟糕的建议,我不想通过将我的应用程序代码与测试代码混合来创建意大利面条代码
所以我的问题 - 是否可以通过使用空闲资源“强制”espresso
等待屏幕上的元素?
我也在考虑创建一些带有一些流利等待元素的辅助方法 - 然后像使用它一样使用它
waitForElement(onView(withId(R.id.elementID))
所以我非常感谢这方面的任何建议。谢谢
解决方案
您可以尝试使用 和 创建自定义等待IdlingResource
操作ViewAction
。最简单的方法是创建一个IdlingResource
回调,ViewTreeObserver.OnDrawListener
通过与 a 匹配来侦听并确定应用何时空闲Matcher<View>
:
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)
}
}
}
}
}
并在根视图上执行此操作:
fun waitForElement(matcher: Matcher<View>) {
onView(isRoot()).perform(waitUntil(hasDescendant(matcher))
}
...
waitForElement(allOf(withId(R.id.elementID), isDisplayed()))
或者,如果视图的属性可以异步更改,您可以执行以下操作:
onView(withId(R.id.elementID)).perform(waitUntil(withText("textChanged!")))
此外,此操作可能不适合活动转换。
推荐阅读
- javascript - 如何使用复选框检查是否选择了相同性别?
- ios - 获取文档目录iOS Swift中每个项目的属性
- ios - Xamarin Forms:移植到 WkWebView 后发生零星崩溃
- php - PHP `json_encode` 错误地将数组转换为 `{}`
- google-sheets - 如何在单个电子表格单元格中获取逗号分隔变量的值和变量计数的总和?
- typescript - Vue CLI 的类型检查服务忽略了内存限制
- corda - 在 Corda 中,如何检查 RPC 连接是否断开并自动重新连接?
- ios - 从多个 BackgroundThreads 到 MainThread 的调用可以同时发生吗?
- python - 在 Python 中读取图例的高度
- wix-extension - 从 WiX 3 迁移到 Wix 4 (4.0.0.5918) 现在会在 Candle.exe (CNDL0200) 中生成错误