从协程访问主线程

时间:2019-04-04 10:53:50

标签: android kotlin android-espresso android-testing kotlin-coroutines

我正在测试一个显示alertDialog的类,我想进行一些UI测试。问题在于对话框和espresso任务都需要在UI线程中运行,但是espresso任务没有执行,它正在等待“某人”从UI中选择项目。

因此,该测试旨在显示alertDialog并选择一个项目(使用espresso),然后断言显示UI的函数的返回结果返回所选项目的值。

这是我要测试的课程:

class UserSelector(private val activity: Activity) {

    suspend fun showUserSelectionDialog(usersAndEmails: Map<String, String>) = suspendCoroutine<String?> { cont ->
        val users: Array<String> = usersAndEmails.keys.toTypedArray()
        val builder = AlertDialog.Builder(activity)
        builder.setTitle(com.build38.fido.asm.R.string.select_username)
                .setItems(users) { _, which ->
                    val username = users[which]
                    cont.resume(usersAndEmails[username])
                }
                .setCancelable(true)
                .setOnCancelListener {
                    cont.resume(null)
                }
        val dialog: AlertDialog = builder.create()
        dialog.show()
    }
}

这是测试类:

@Rule @JvmField
var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)

private lateinit var userSelector: UserSelector

@Before
fun setUp() {
    userSelector = UserSelector(mActivityRule.activity)
}

@Test
fun clickOnFirstItem() {
    val usernamesAndEmails = mutableMapOf<String,String>()
    usernamesAndEmails.put("Username1", "Email1")
    usernamesAndEmails.put("Username2", "Email2")
    var email = ""
    runBlocking {
        withContext(Dispatchers.Main) {
            email = userSelector.showUserSelectionDialog(usernamesAndEmails)!!
        }
        onView(withText("Username2"))
                .perform(ViewActions.click())

    }
    assertEquals("Username1", email)
}

1 个答案:

答案 0 :(得分:0)

由于正在等待对话框同步完成,因此不执行单击。 withContext在不同的上下文中同步执行代码(在大多数情况下,这只是另一个线程)。

这里想要的实际上是对话框显示的异步执行。因此,使用launch生成可以异步执行的协程。借助结构化的并发功能,您不必在runBlocking的末尾等待它。

@Test
fun clickOnFirstItem() {
    val usernamesAndEmails = mutableMapOf<String,String>()
    usernamesAndEmails.put("Username1", "Email1")
    usernamesAndEmails.put("Username2", "Email2")
    var email = ""
    runBlocking {
        launch(Dispatchers.Main) {
            email = userSelector.showUserSelectionDialog(usernamesAndEmails)!!
        }
        onView(withText("Username2"))
                .perform(ViewActions.click())

    }
    assertEquals("Username1", email)
}