안드로이드 UI 테스트를 하던 중 A 화면에서 버튼을 클릭했을 때 B 화면으로 넘어가는 동작이 있었다. 그러고 나서 B 화면에 알맞은 text가 보이는지 체크하는데 아래와 같은 오류가 떴다.

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with ...

넘어가는 과정을 자세히 보면 A 화면 -> animation -> B 화면으로 진행된다. 짐작되는 원인으로는 animation이 동작하는 와중에 B 화면의 text를 찾아서 생긴 것으로 보인다. Espresso 입장에서는 아직 B 화면이 띄어지지 않았기 때문에, 당연히 매칭되는 뷰가 없다는 Exception을 던지는 것이다.

위 상황에 맞는 간단한 예제 테스트 코드를 작성해보면..

@Test
public void testGoToNextPage() throws Exception {
    // Click button in page 'A'.
    onView(withId(R.id.button))
        .perform(click());

    // Check text is appered in page 'B'.
    onView(withText("B 화면"))
        .check(matches(isDisplayed()));
}

이 문제는 UiDevice 클래스의 waitForIdle()을 이용하면 간단하게 해결 된다. waitForIdle()에 대한 설명을 보면 아래와 같이 나와 있다.

Waits for the current application to idle. Default wait timeout is 10 seconds.

즉, B 화면에 text가 보이는지 체크하기 전에 해당 메소드를 호출하면 된다.

private UiDevice mDevice;

@Before
public void setUp() throws Exception {
    // Initialize UiDevice instance.
    mDevice = UiDevice.getInstance(getInstrumentation());
}

@Test
public void testGoToNextPage() throws Exception {
    // Click button in page 'A'.
    onView(withId(R.id.button))
        .perform(click());

    // Call method to wait before check.
    mDevice.waitForIdle();

    // Check text is appered in page 'B'.
    onView(withText("B 화면"))
        .check(matches(isDisplayed()));
}

UiDevice는 Testing UI for Multiple Apps에서 사용되고 있는데, 나는 Testing UI for a Single App 을 참고하여 Espresso testing framework로 테스트 코드를 짰다.

사실 아직 이 둘의 차이를 정확히 모르겠다. 그래서 이 방법이 정석적인? 방법이라고 말은 못하지만, 우선 원하는 대로 동작은 했으니… 추후에 일반적으로 사용되는 방법을 찾아봐야겠다. :)