我的Activity有一个EditText和一个Button。按下按钮时,将调用长时间运行的功能。在此期间,应禁用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!"
}
fun onButtonClicked() {
// data binding field to disable EditText
loading = true
launch(CommonPool) {
// make "network call"
val data = getData().await()
// reenable EditText
loading = false
}
}
@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()))
}
一般来说,你不应该处理视图中的任何逻辑(活动,片段等),它应该在一个单独的逻辑处理程序(如ViewModel,Presenter或..)中完成。
您可以使用框架(如Mockito或MockK)来spy
您的活动,并模拟getData()
方法以始终快速返回,这样您的测试用例不需要等待它。
要使用mockito监视您的活动,您可以使用this回答中的信息,并使用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).
}
}