微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Robolectric/Espresso 测试中避免睡眠

如何解决在 Robolectric/Espresso 测试中避免睡眠

我正在使用 Robolectric 编写端到端测试,该测试触发对 OkHttp MockWebServer 的 HTTP 调用。它看起来像这样:

val mockServer = MockWebServer()
launchFragmentInHiltContainer<LoginFragment>()

onView(withId(R.id.loginEditText)).perform(typeText("loginId"))
onView(withId(R.id.loginButton)).perform(click())

// At this point,the fragment's viewmodel starts an HTTP request using Retrofit/OkHttp
// The callback causes a LiveData viewmodel to post an event,which the fragment listens
// to,and updates the UI accordingly

val request = mockServer.takeRequest()
assertEquals("/login",req.path)

Thread.sleep(1000)
shadowOf(getMainLooper()).idle()

// Without the two lines above,the test reaches this point before 
// the mock server is done calling back
onView(withId(R.id.loggedInView)).check(matches(isdisplayed()))

如何确保在单击登录按钮后完全处理了服务器响应?

解决方法

我不是 100% 确定,但尝试一次

制作一个这样的对象

 Object syncObject = new Object();

然后用这个替换你的 Thread.sleep(1000)

synchronized (syncObject) {
          syncObject.notify();
        }

如果它不能正常工作,那么用 wait() 代替 notify()

,

您可以使用 Espresso idling resources(链接:Documentation)来实现这一点并摆脱那个根本不是一个好的选择的 Thread.sleep()。 由于您使用的是 Okhttp,因此已经有一个库可以为您解决问题: Okhttp Idling Resource

,

您不需要向代码中注入等待语句来检测请求的终止。 您可能很清楚,单独使用 Thread.sleep(X) 是解决此问题的非常糟糕的尝试,因为您的请求每次都需要更改,您可能会面临等待不够或等待太多的风险。

Idling Resources 是一种更好的尝试,但存在多个问题。 1)在每次检查队列是否为空(没有请求)之间,它让你等待 5 秒。当您执行大量测试时,这会很快堆积起来。 2)您需要更改您正在测试的代码以启用空闲资源。 3)它不适用于所有类型的异步请求。

我(和很多其他人)在 Espresso 中使用自定义重试功能来解决这个问题。

下面的函数检查条件是否成立,如果不成立,它会在 X 毫秒后再次检查。这样,您的测试将在请求完成后立即进行(而不是 IdlingResources 中的 5 秒等待时间)。您需要做的就是等待在您的请求被发送之前不成立的条件。

fun waitForCondition(matcher: Matcher<View>,timeout: Long = 15000L,condition: (View?) -> Boolean) {

    require(timeout > 0) { "Require timeout>0" }

    var success = false
    lateinit var exception: NoMatchingViewException
    val loopCounter = timeout / 250L
    (0..loopCounter).forEach {
        onView(matcher).check { view,noViewFoundException ->
            if (condition(view)) {
                success = true
                return@check
            } else {
                Thread.sleep(250)
                exception = noViewFoundException
            }
        }
        if (success) {
            return
        }
    }
    throw exception
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。