Android Instrumentation 在协程中被阻止

Dre*_*Dre 5 android coroutine kotlin android-espresso

我的活动有一个 EditText 和一个按钮。当按钮被按下时,一个长时间运行的函数被调用。在此期间,应禁用 EditText。当函数完成后,应该重新启用 EditText。这在运行应用程序时工作正常,但是我编写了一个 Espresso 单元测试来测试这种行为,该行为似乎行为不正确。

看起来长时间运行的功能会暂停运行超过 3 秒的单元测试。一旦长时间运行的函数完成,单元测试然后测试 EditText 是否被禁用,它不再是因为任务完成并且loading变量被设置回false

我希望单元测试然后启动该函数,因为它在协程中运行,它将继续到下一行以检查 EditText 是否被禁用。

我已经尝试了 CommonPool、UI、launch、async、Deferred 等的所有不同变体,但似乎没有得到正确的行为。

suspend fun getData(): String {
    // simulate network request delay
    delay(3000)                       
    return "Hello, world!"
}
Run Code Online (Sandbox Code Playgroud)

fun onButtonClicked() {
    // data binding field to disable EditText
    loading = true 

    launch(CommonPool) {
        // make "network call"
        val data = getData().await()

        // reenable EditText
        loading = false
    }
}
Run Code Online (Sandbox Code Playgroud)

@Test
fun disableEditText() {
    // check the EditText starts off enabled
    onView(withId(R.id.edit_text))
            .check(matches(isEnabled()))

    // click the Button to simulate the network call
    onView(withId(R.id.button))
            .perform(click())

    // check the EditText is disabled
    onView(withId(R.id.edit_text))
            .check(matches(not(isEnabled()))
}
Run Code Online (Sandbox Code Playgroud)

Adi*_*rzi 1

一般来说,您不应该在视图(活动、片段等)内处理任何逻辑,而应该在单独的逻辑处理程序(如 ViewModel、Presenter 或...)中完成。

您可以spy使用框架(如 Mockito 或 MockK)进行活动,并模拟getData()方法以始终快速返回,这样您的测试用例就不需要等待它。

要使用mockito监视您的活动,您可以使用此答案中的信息,并使用when(activity.getData()).thenReturn("")来模拟该方法。由于您正在模拟协程,因此您需要使用runBlocking它来运行测试。

class MainActivityTest {
    internal var subject: MainActivity

    val activityFactory: SingleActivityFactory<MainActivity> =
        object : SingleActivityFactory<MainActivity>(MainActivity::class.java) {
            protected fun create(intent: Intent): MainActivity {
                subject = spy(getActivityClassToIntercept())
                return subject
            }
        }

    @Rule
    var testRule: ActivityTestRule<MainActivity> = ActivityTestRule(activityFactory, true, true)

    @Test
    fun sampleTest() = runBlocking<Unit> {
        `when`(subject.getData()).thenReturn("")
        //verify(subject).
    }

}
Run Code Online (Sandbox Code Playgroud)