现有 Android UI 测试在切换到 AndroidJUnitRunner 后停止工作

Existing Android UI tests stopped working after switching to AndroidJUnitRunner

我们对相机功能进行了一些 UI 测试,在我们从 InstrumentationTestRunner 切换到 AndroidJUnitRunner 作为我们迁移到 Espresso/JUnit4 的一部分之后,由于调用 getActivity():

时频繁出现 RuntimeException,我们无法再 运行 可靠地进行现有测试
java.lang.RuntimeException: Could not launch intent Intent { flg=0x14000000 cmp=com.cookbrite.dev/com.cookbrite.ui.ReceiptCaptureActivity (has extras) } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was 1434471981236 and now the last time the queue went idle was: 1434471981236. If these numbers are the same your activity might be hogging the event queue.
at android.support.test.runner.MonitoringInstrumentation.startActivitySync(MonitoringInstrumentation.java:315)
at android.test.InstrumentationTestCase.launchActivityWithIntent(InstrumentationTestCase.java:119)
at android.test.ActivityInstrumentationTestCase2.getActivity(ActivityInstrumentationTestCase2.java:106)
at com.cookbrite.step2_functional.ui.receipt.ReceiptCaptureTest.getActivity(ReceiptCaptureTest.java:43)

为了提高可读性,引用 RuntimeException 中的错误消息:

Could not launch intent Intent { flg=0x14000000 cmp=com.cookbrite.dev/com.cookbrite.ui.ReceiptCaptureActivity (has extras) } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was 1434471981236 and now the last time the queue went idle was: 1434471981236. If these numbers are the same your activity might be hogging the event queue.

我们现有的测试使用 Robotium。尝试使用 Espresso 编写相同的测试产生了类似的错误,这可能是由于相机预览不断更新 UI。但是,即使将预览设置为 INVISIBLE,我们仍然 运行 遇到 Espresso 的这个问题。

任何 ideas/pointers 关于如何解决这个问题(除了返回 InstrumentationTestRunner)?

错误输出表明测试 class 扩展了 ActivityInstrumentationTestCase2。我不确定迁移到新的 ActivityTestRule 是否会对您的情况有任何影响,但值得快速检查一下。将其放在答案而不是评论中以包含示例代码:

@RunWith(AndroidJUnit4.class)
public class ReceiptCaptureTestNew {
    private ReceiptCaptureActivity mReceiptCaptureActivity;

    @Rule
    public ActivityTestRule<mReceiptCaptureActivity> mActivityRule =
            new ActivityTestRule<>(mReceiptCaptureActivity.class);

    @Before
    public void setUp() throws Exception {
        mReceiptCaptureActivity = mActivityRule.getActivity();
    }

    @After
    public void tearDown() throws Exception {
        // Call finish() on all activities in @After to avoid exceptions in
        // later calls to getActivity() in subsequent tests
        mReceiptCaptureActivity.finish();
    }

    @Test
    public void testPreconditions() {
        assertNotNull(mReceiptCaptureActivity);
        assertThat(mReceiptCaptureActivity.hasWindowFocus(), is(true));
    }
}

最后,我们将 UI 更改为延迟相机预览启动,这样 MonitoringInstrumentation 就不会对所有 UI 更新感到不安。此外,SurfaceViewTextureView post UI 都会在连接相机后立即更新,即使在 INVISIBLEGONE 状态下也是如此。这就是导致 MonitoringInstrumentation 在我们的案例中放弃的原因。

如果您有一个以常量 UI 更新开始的测试,您可能需要考虑暂停该操作,直到 startActivitySync() 完成并且您从 getActivity() 获得非空结果.