advanced espresso #io16 extend seoul

Post on 17-Jan-2017

1.688 Views

Category:

Internet

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

정승욱

Google Developer Expert토스랩 - JANDI Android 개발자

Advanced Espresso

안드로이드 테스트

안드로이드

스튜디오

안드로이드 테스트서포트 라이브러리

AndroidEpsresso

UI 테스트 흐름

onView(withId(R.id.fab)).perform(click());

onView(withItemText("Jason")).perform(click());

onView(withId(R.id.et_message))

.perform(typeText("test"));

onView(withId(R.id.btn_send)).perform((click());

onView(withId(android.R.id.home).perform(click());

onView(withItemText("Jason"))

.check(matches(isDisplayed()));

코드로 보는 UI 테스트

onView(withId(R.id.fab)).perform(click());

onView(withItemText("Jason")).perform(click());

onView(withId(R.id.et_message))

.perform(typeText("test"));

onView(withId(R.id.btn_send)).perform((click());

onView(withId(android.R.id.home).perform(click());

onView(withItemText("Jason"))

.check(matches(isDisplayed()));

코드로 보는 UI 테스트

onView(withId(R.id.fab)).perform(click());

onView(withItemText("Jason")).perform(click());

onView(withId(R.id.et_message))

.perform(typeText("test"));

onView(withId(R.id.btn_send)).perform((click());

onView(withId(android.R.id.home).perform(click());

onView(withItemText("Jason"))

.check(matches(isDisplayed()));

코드로 보는 UI 테스트

onView(withId(R.id.fab)).perform(click());

onView(withItemText("Jason")).perform(click());

onView(withId(R.id.et_message))

.perform(typeText("test"));

onView(withId(R.id.btn_send)).perform((click());

onView(withId(android.R.id.home).perform(click());

onView(withItemText("Jason"))

.check(matches(isDisplayed()));

코드로 보는 UI 테스트

Espresso 의 구분

onView(Matcher<View>) // ViewMatcher -> ViewInteraction .perform(ViewAction) // ViewAction

onView(Matcher<View>) .check(ViewAssertion); // ViewAssertion

ViewMatcher

View 에 접근하기 위한 객체

Activity 나 Fragment 를 사용하면?

➡� View 가 Null 이면? ➡� Test에 NPE 처리를?

“ViewMatcher 는 뷰에 접근하는 과정에서의 오동작을 에러가 아닌 테스트 실패로 간주할 수 있도록 도와준다.”

ViewInteraction

UI 테스트의 시작점

접근한 View 정보를 담고 있음

View 의 동작을 제어 : 클릭, 텍스트 입력 등

View 의 정보를 검증 기능 제공 : 화면에 보이는지..

ViewAction

뷰에 클릭 또는 텍스트 입력등 다양한 동작을 제어함

동작이 완료될 때까지 대기하도록 함

ViewInteraction.java

Idle or not?

handler.postDelayed(runnable, 5000);

Main Looper 는 Idle 상태일까요?

LooperIdlingResource.java

QueueInterrogator.java

Custom IdlingResource 예시

@Overridepublic boolean isIdleNow() { boolean idle = !isIntentServiceRunning(); if (idle && resourceCallback != null) { resourceCallback.onTransitionToIdle(); } return idle;}

private boolean isIntentServiceRunning() { ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo info : manager.getRunningServices(Integer.MAX_VALUE)) { if (RepeatService.class.getName().equals(info.service.getClassName())) { return true; } } return false;}

Custom IdlingResource 적용

@Beforepublic void registerIntentServiceIdlingResource() { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); idlingResource = new IntentServiceIdlingResource( instrumentation.getTargetContext()); Espresso.registerIdlingResources(idlingResource);}

@Afterpublic void unregisterIntentServiceIdlingResource() { Espresso.unregisterIdlingResources(idlingResource);}

구글의 팁

복사 붙여넣기 하지마라

복붙 금지!!!

@Test public void testXXX() { onView(withId(R.id.fab)).xxx;}

@Test public void testYYY() { onView(withId(R.id.fab)).yyy;}

만약 Resource 의 ID 가 바뀐다면?

Robot 예제

42 입력

onView(withText("4")).perform(click());onView(withText("2")).perform(click());

Robot.input(42);

public static void input(int x) { String y = String.valueOf(x); for (int i = 0; i < y.lengn(); i++) { onView(withText(String.valueOf(y.charAt(i)))) .perform(click()); }}

가능한 제공되는 Matcher 를 사용해라

CheatSheet

CountingIdlingResource 를 사용해라

CountingIdlingResource.java

public class CountingIdlingResource {

public void increment();

public void decrement();

}

단 Timeout 설정을 같이 해주세요.

public class IdlingPolicies {

public static void setMasterPolicyTimeout(long timeout,TimeUnit unit);

public static void setIdlingResourceTimeout(long timeout, TimeUnit unit);

}

기본값- IdlingResource : 5초- MasterPolicy : 26초

뷰의 정보가 아닌 동작에 집중해라.

동작의 결과에 주목하자.

4가 쓰여진 뷰의 x-y 위치 같은 것은 잊어라

4가 씌여진 뷰가 있는지를 검증하라.

Large Test 보단 Small Test 를 많이 써라

LargeTest

Small Test

1 2

2 3

3 4

원하는 화면을 바로 호출해라.

MyActivityTest.java

@Rule

new ActivityTestRule<MyActivity>(MyActivity.class) {

@Override protected Intent getActivityIntent() {

Intent intent = new Intent();

intent.putExtra(...);

return intent;

}

}

MyActivityTest.java

@Rulepublic ActivityTestRule<MyActivity> rule = new ActivityTestRule<MyActivity>(MyActivity.class, true, false);

@Beforepublic void setUp() { int extra = getExtraInt(); Intent intent = new Intent(); rule.launchActivity(intent);}

통제된 환경에서만 테스트 해라

외부 앱 실행은 Intent 를 획득하라

Intent 획득

@Testpublic void test() { Intents.init(); ActivityResult result = createImageCaptureResult(); intending(hasAction(IMAGE_CAPTURE)).responseWith(result); // test something Intents.release();}

Intent 획득

@Rulepublic IntentTestRule<MyAct> rule = new IntentTestRule<>(MyAct.class);

@Testpublic void test() { ActivityResult result = createImageCaptureResult(); intending(hasAction(IMAGE_CAPTURE)).responseWith(result); // test something}

애니메이션을 핸들링 하기

이따금 커스텀 애니메이션은 과도하게 Handler 를 사용하기 때문에 Idle 상태를 유지하기 어렵게 만든다.

UI 테스트에 실패했을 때...

Espresso ViewHierarchy Log

Test 의 Log Console 을 읽는다.

android.support.test.espresso.AmbiguousViewMatcherException: 'with id: is <2131493330>' matches multiple views in the hierarchy. Problem views are marked with '****MATCHES****' below.

+------------->ImageView{id=2131493330, res-name=item_image, desc=Image, visibility=VISIBLE, width=262, height=262, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0} ****MATCHES****

+------------->ImageView{id=2131493330, res-name=item_image, desc=Image, visibility=VISIBLE, width=262, height=262, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0} ****MATCHES**** |

Custom FailureHandler

public interface FailureHandler {

public void handle(Throwable error, Matcher<View> viewMatcher);

}

Espresso.setFailureHandler(handler);

느린 기기 Test 시 주의사항

Settings → Accessiblility → Touch and hold delay

Long 으로 전환

Animation 비활성화

Accessibility Test 시 주의사항

AccessibilityValidator.enable()

참고 자료

문서

- https://google.github.io/android-testing-support-library/

영상

- https://www.youtube.com/watch?v=isihPOY2vS4

예제 코드- https://github.com/googlesamples/android-testing- https://github.com/googlesamples/android-testing-templates- https://github.com/googlesamples/android-architecture

top related