繁体   English   中英

在 Robolectric/Espresso 测试中避免睡觉

[英]Avoiding sleep in Robolectric/Espresso test

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

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

 Object syncObject = new Object();

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

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

如果它不能正常工作,则将wait()代替notify()

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

您无需向代码中注入等待语句来检测请求的终止。 您可能很清楚Thread.sleep(X)单独解决这个问题是一个非常糟糕的尝试,因为您的请求每次都发生变化,并且您可能等待不够或等待太多。

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

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

下面的 function 检查条件是否成立,如果不成立,则在 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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM