Espresso中perform方法报错‘无法在主线程调用’的解决问询
Espresso测试调用
perform时报主线程错误的解决方法 问题现象
编写Activity的Instrumentation测试时,调用onView(...).perform(typeText(...), closeSoftKeyboard())触发报错:
Method cannot be called on the main application thread
测试代码
class LoginActivityTests { @get:Rule var rule = ActivityScenarioRule(LoginActivity::class.java) @Test fun whenClickLoginStoresDomainInConnectionManager() { val domainName = "foo" val scenario = rule.scenario scenario.onActivity { onView(withId(R.id.domainEditText)).perform(typeText(domainName), closeSoftKeyboard()) } } }
报错堆栈
java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main) at androidx.test.internal.util.Checks.checkState(Checks.java:111) at androidx.test.internal.util.Checks$1.checkNotMainThread(Checks.java:150) at androidx.test.internal.util.Checks.checkNotMainThread(Checks.java:130) at androidx.test.espresso.ViewInteraction.postAsynchronouslyOnUiThread(ViewInteraction.java:1) at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:4) at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:8)
尝试过runOnUiThread或@UiThreadTest注解,均得到相同错误。
原因分析
scenario.onActivity的回调逻辑是运行在应用的主线程中的,但Espresso的核心API(如onView、perform)要求必须在测试专用的后台线程调用——Espresso内部会自动处理切换到UI线程执行用户操作的逻辑,把Espresso代码套在主线程回调里,完全违背了它的线程要求,因此触发了非法状态检查。
解决方法
直接将Espresso的代码从scenario.onActivity的代码块中移出,放在@Test方法的顶层即可,不需要手动处理线程切换。修正后的代码:
class LoginActivityTests { @get:Rule var rule = ActivityScenarioRule(LoginActivity::class.java) @Test fun whenClickLoginStoresDomainInConnectionManager() { val domainName = "foo" // 直接调用Espresso API,无需包裹在onActivity中 onView(withId(R.id.domainEditText)).perform(typeText(domainName), closeSoftKeyboard()) // 如果需要直接操作Activity实例,单独用onActivity处理,与Espresso代码分离 rule.scenario.onActivity { activity -> // 这里编写需要直接访问Activity内部状态或方法的逻辑 } } }
为什么示例测试无需处理线程
示例中的测试代码都是直接在@Test方法中调用Espresso API,没有嵌套在onActivity这类主线程回调里,完全符合Espresso的线程要求——Espresso会自动完成测试线程到UI线程的切换,因此不需要额外处理线程问题。
内容的提问来源于stack exchange,提问作者user1713450
相关产品推荐
相关产品推荐

