java - Android Instrumentation 测试 - UI 线程问题

标签 java android multithreading testing junit

我正在尝试为我的 Android 应用编写仪器测试。

我遇到了一些奇怪的线程问题,我似乎找不到解决方案。

我的原始测试:

@RunWith(AndroidJUnit4.class)
public class WorkOrderDetailsTest {

    @Rule
    public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class);

    @Test
    public void loadWorkOrder_displaysCorrectly() throws Exception {
        final WorkOrderDetails activity = activityRule.getActivity();

        WorkOrder workOrder = new WorkOrder();
        activity.updateDetails(workOrder);

        //Verify customer info is displayed
        onView(withId(R.id.customer_name))
                .check(matches(withText("John Smith")));
    }
}

这导致了

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

...

com.kwtree.kwtree.workorder.WorkOrderDetails.updateDetails(WorkOrderDetails.java:155)

updateDetails() 方法唯一做的就是一些 setText() 调用。

经过一番研究,似乎在我的测试中添加 UiThreadTestRuleandroid.support.test.annotation.UiThreadTest 注释可以解决问题。

@UiThreadTest:

@RunWith(AndroidJUnit4.class)
public class WorkOrderDetailsTest {

    //Note: This is new
    @Rule
    public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();

    @Rule
    public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class);

    @Test
    @UiThreadTest //Note: This is new
    public void loadWorkOrder_displaysCorrectly() throws Exception {
        final WorkOrderDetails activity = activityRule.getActivity();

        WorkOrder workOrder = new WorkOrder();
        activity.updateDetails(workOrder);

        //Verify customer info is displayed
        onView(withId(R.id.customer_name))
                .check(matches(withText("John Smith")));
    }
}

java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main)

(注意:此堆栈跟踪中的所有方法都不是我的代码)

这似乎给了我混合的结果......如果它需要在创建 View 的原始线程上运行但不能在主线程上运行,它应该在哪个线程上运行?

非常感谢任何帮助或建议!

最佳答案

这些仪器测试在他们的自己的应用程序中运行。这也意味着,它们在自己的线程中运行。

您必须将仪器视为与实际应用一起安装的东西,因此您可能的交互是“有限的”。

您需要从应用程序的 UIThread/主线程调用所有 View 方法,因此从您的检测线程调用 activity.updateDetails(workOrder);不是应用程序主线程。这就是引发异常的原因。

你可以在你的主线程上运行你需要测试的代码,就像你在你的应用程序中使用不同的线程调用它一样

activity.runOnUiThread(new Runnable() {
    public void run() {
        activity.updateDetails(workOrder);
    }
}

通过这个运行,你的测试应该可以工作了。

您收到的非法状态异常似乎是由于您与规则的交互。 documentation状态

Note that instrumentation methods may not be used when this annotation is present.

如果您在 @Before 中开始/获取 Activity ,它也应该可以工作。

关于java - Android Instrumentation 测试 - UI 线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35183981/

相关文章:

java - 如何让代码在继续执行 Java 中的 println 之前等待对象?

java - 在android中使用海绵城堡

android - Android:按钮会在onClick播放2种声音

c# - 在后台线程上初始化时,我的字段应该是易变的吗?

c++ - Abort() 已被调用 - Connect Function multithreads Cpp

c# - 确定从转储文件中抛出异常的线程

java - Mockito 如何模拟和断言抛出的异常?

java - 将 Matchers.eq() 与其他模拟值一起使用时出现 InvalidUseOfMatchersException

java - 如何将对象实例存储为 EJB3 实体的字段?

android - 为什么 SDL_Window 是不完整的类型?