Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UiAutomator2와 AWS Device Farm을 활용한 안드로이드 UI 테스트 자동화

UiAutomator2와 AWS Device Farm을 활용한 안드로이드 UI 테스트 자동화

많은 사람들이 UI는 까다롭고 복잡하다는 편견을 가지고 있지만, UI 테스트를 매뉴얼하게 진행한다면 많은 시간과 비용이 소모됩니다.
스타트업 '숨고'에서 자동화된 UI 테스팅을 수행하며 얻은 값진 팁과 교훈을 공유합니다.

Yoonjae Yoo

March 25, 2017
Tweet

More Decks by Yoonjae Yoo

Other Decks in Technology

Transcript

  1. UIA UTOM ATOR2৬ DEVICEFARM ਸ ഝਊೠ U I ప झ

    ౟ ੗ ز ച Y O O N J A E Y O O
  2. ੗ ز ప झ ౟ ࣻ ز ప झ ౟

    ગ਷ ߧਤ੄ పझ౟ ݆਷ ੋ۱ ೙ਃ ݆਷ दр ࣗݽ ׮নೠ ӝӝܳ ഛࠁ೧ঠ ೣ 1 2 3 4 և਷ ߧਤ੄ పझ౟ ੸਷ ੋ۱ਵ۽ ࣻ೯ оמ ࡅܲ పझ౟ ௿ۄ਋٘۽ పझ౟, पઁ ӝӝо ೙ਃহ਺ 1 2 3 4
  3. U I A U T O M A T O

    R 2 U I A U T O M A T O R 2 ! " #  ए਍ API оߺ׮ ࠶ۑ߅झ పझ౟ ҳӖ੄ ૑ਗ
  4. A P I ࣗ ѐ I N T O R

    O D U C T I O N T O A P I • By : BySelector ё୓ܳ ࢤࢿೞח ਬ౰ܻ౭ ௿ېझ. • BySelector : ചݶ࢚ীࢲ UI ਃࣗܳ ଺ӝ ਤೠ ࢶఖ੗. • UiDevice : ӝӝ੄ ࢚కী ੽ӔೞҊ ӝӝܳ ઁযೡ ࣻ ੓ח ௿ېझ. • UiObject2 : UiAutomator 2.0ী ୶оػ ௿ېझ۽ ؊ ъ۱ೠ ӝמਸ ૑ਗ. ਤ ֎о૑ ௿ېझ ࢎਊߨ݅ ঌইب ؀ࠗ࠙੄ పझ౟ܳ ੘ࢿ оמ.
  5. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D // app/build.gradle dependencies { ... androidTestCompile ‘com.android.support.test.uiautomator:uiautomator-v18:2.1.2' } @RunWith(AndroidJUnit4.class)
 public abstract class BaseTest {
 protected UiDevice mDevice;
 
 @Before
 public void before() {
 mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 assertNotNull(mDevice);
 openApp();
 }
 }
  6. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D // app/build.gradle dependencies { ... androidTestCompile ‘com.android.support.test.uiautomator:uiautomator-v18:2.1.2' } @RunWith(AndroidJUnit4.class)
 public abstract class BaseTest {
 protected UiDevice mDevice;
 
 @Before
 public void before() {
 mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 assertNotNull(mDevice);
 openApp();
 }
 }
  7. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D // BaseTest.java public static final long LAUNCH_TIMEOUT = 10000; public static final long DEFAULT_TIMEOUT = 1500;
 
 private void openApp() {
 mDevice.pressHome();
 
 Context context = InstrumentationRegistry.getInstrumentation().getContext();
 Intent intent = context.getPackageManager().getLaunchIntentForPackage(BuildConfig.APPLICATION_ID);
 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
 context.startActivity(intent);
 
 mDevice.wait(Until.hasObject(By.pkg(BuildConfig.APPLICATION_ID).depth(0)), LAUNCH_TIMEOUT);
 }
  8. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D // BaseTest.java public static final long LAUNCH_TIMEOUT = 10000; public static final long DEFAULT_TIMEOUT = 1500;
 
 private void openApp() {
 mDevice.pressHome();
 
 Context context = InstrumentationRegistry.getInstrumentation().getContext();
 Intent intent = context.getPackageManager().getLaunchIntentForPackage(BuildConfig.APPLICATION_ID);
 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
 context.startActivity(intent);
 
 mDevice.wait(Until.hasObject(By.pkg(BuildConfig.APPLICATION_ID).depth(0)), LAUNCH_TIMEOUT);
 }
  9. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D // BaseTest.java public static final long LAUNCH_TIMEOUT = 10000; public static final long DEFAULT_TIMEOUT = 1500;
 
 private void openApp() {
 mDevice.pressHome();
 
 Context context = InstrumentationRegistry.getInstrumentation().getContext();
 Intent intent = context.getPackageManager().getLaunchIntentForPackage(BuildConfig.APPLICATION_ID);
 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
 context.startActivity(intent);
 
 mDevice.wait(Until.hasObject(By.pkg(BuildConfig.APPLICATION_ID).depth(0)), LAUNCH_TIMEOUT);
 }
  10. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D // BaseTest.java public static final long LAUNCH_TIMEOUT = 10000; public static final long DEFAULT_TIMEOUT = 1500;
 
 private void openApp() {
 mDevice.pressHome();
 
 Context context = InstrumentationRegistry.getInstrumentation().getContext();
 Intent intent = context.getPackageManager().getLaunchIntentForPackage(BuildConfig.APPLICATION_ID);
 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
 context.startActivity(intent);
 
 mDevice.wait(Until.hasObject(By.pkg(BuildConfig.APPLICATION_ID).depth(0)), LAUNCH_TIMEOUT);
 }
  11. U I ਃ ࣗ ଺ ӝ F I N D

    I N G U I E L E M E N T S పझ౟ܳ ਤ೧ࢲח UiObject2ܳ ݢ੷ ଺ইঠ ೞݴ, BySelector ࢶఖ੗۽ UiDevice ীࢲ ഑਷ UiObject2 ীࢲ (ೞਤ ਃࣗܳ) Ѩ࢝ਸ ೡ ࣻ ੓׮. • UiDevice#findObject(BySelector selector) • UiDevice#findObjects(BySelector selector) • UiObject2#findObject(BySelector selector) • UiObject2#findObjects(BySelector selector) ex) UiObject2 scrollable = mDevice.findObject(By.scrollable(true));
 UiObject2 clickable = scrollable.findObject(By.clickable(true));
  12. U I ਃ ࣗ ଺ ӝ F I N D

    I N G U I E L E M E N T S ഑਷ UiObject2 ઓ੤ ৈࠗ݅ Ѩࢎೡ ࣻ ੓׮. • UiDevice# hasObject(BySelector selector) • UiObject2# hasObject(BySelector selector) ex) assertTrue(mDevice.hasObject(By.scrollable(true)));
 assertTrue(mDevice.findObject(By.scrollable(true)).hasObject(By.scrollable(true)));
  13. ࢶ ఖ ੗ ࢤ ࢿ C R E A T

    I N G S E L E C T O R UI ਃࣗܳ Ѩ࢝ೞח ؘ ೙ਃೠ ࢶఖ੗ੋ BySelectorח ׮਺ ઺ ೠо૑ ߑधਵ۽ ࢤࢿೡ ࣻ ੓׮. • ಁః૑ • ௿ېझ • ஶబ౟ ࢸݺ • ܻࣗझ • ఫझ౟ • ࢚క(checkable, checked, clickable, enabled, focusable, focused, longClickable, scrollable, selected) • ೞਤ ҙ҅
  14. ࢶ ఖ ੗ ࢤ ࢿ : ಁ ః ૑ C

    R E A T I N G S E L E C T O R : P A C K A G E ౠ੿ ಁః૑ী ࣘೞח ਃࣗܳ ଺ਸ ࣻ ੓׮. • By.pkg(String applicationPackage) • By.pkg(Pattern applicationPackage) ex) BySelector selector1 = By.pkg(“com.soomgo"); BySelector selector2 = By.pkg(Pattern.compile("com\\.soomgo.+"));
  15. ࢶ ఖ ੗ ࢤ ࢿ : ௿ ې झ C

    R E A T I N G S E L E C T O R : C L A S S ౠ੿ ௿ېझী ೧׼ೞח ਃࣗܳ ଺ਸ ࣻ ੓׮. • By.clazz(String className) • By.clazz(String packageName, String className) • By.clazz(Class clazz) • By.clazz(Pattern className) ex) BySelector selector1 = By.clazz("android.support.v7.widget.RecyclerView");
 BySelector selector2 = By.clazz("android.support.v7.widget", "RecyclerView");
 BySelector selector3 = By.clazz(RecyclerView.class);
 BySelector selector4 = By.clazz(Pattern.compile("[^.]+\\.RecyclerView"));
  16. ࢶ ఖ ੗ ࢤ ࢿ : ஶ బ ౟ ࢸ

    ݺ C R E A T I N G S E L E C T O R : C O N T E N T D E S C R I P T I O N ஶబ౟ ࢸݺਵ۽ ਃࣗܳ ଺ਸ ࣻ ੓׮. • By.desc(String contentDescription) • By.descContains(String substring) • By.descStartsWith(String substring) • By.descEndsWith(String substring) • By.desc(Pattern contentDescription) ex) BySelector selector1 = By.desc("button");
 BySelector selector2 = By.desc(Pattern.compile(".+button"));
  17. ࢶ ఖ ੗ ࢤ ࢿ : ܻ ࣗ झ C

    R E A T I N G S E L E C T O R : R E S O U R C E ܻࣗझ ID۽ ਃࣗܳ ଺ਸ ࣻ ੓׮. • By.res(String resourceName) • By.res(String resourcePackage, String resourceId) • By.res(Pattern resourceName) ex) BySelector selector1 = By.res("com.soomgo:id/button_sign_in");
 BySelector selector2 = By.res("com.soomgo", "button_sign_in");
 BySelector selector3 = By.res(Pattern.compile(".*:id/button_sign_in"));
  18. ࢶ ఖ ੗ ࢤ ࢿ : ఫ झ ౟ C

    R E A T I N G S E L E C T O R : T E X T ಴दغח ఫझ౟۽ ਃࣗܳ ଺ਸ ࣻ ੓׮. • By.text(String text) • By.textContains(String substring) • By.textStartsWith(String substring) • By.textEndsWith(String substring) • By.text(Pattern regex) ex) BySelector selector1 = By.text("۽Ӓੋ");
 BySelector selector2 = By.text(Pattern.compile(".*۽Ӓੋ"));
  19. ࢶ ఖ ੗ ࢤ ࢿ : ࢚ క C R

    E A T I N G S E L E C T O R : S T A T E ࢚క۽ ਃࣗܳ ଺ਸ ࣻ ੓׮. • By.checkable(boolean isCheckable) • By.checked(boolean isChecked) • By.clickable(boolean isClickable) • By.enabled(boolean isEnabled) • By.focusable(boolean isFocusable) • By.focused(boolean isFocused) • By.longClickable(boolean isLongClickable) • By.scrollable(boolean isScrollable) • By.selected(boolean isSelected)
  20. ࢶ ఖ ੗ ࢤ ࢿ : ೞ ਤ ҙ ҅

    C R E A T I N G S E L E C T O R : H I E R A R C H Y ೞਤ ਃࣗ ನೣ ҙ҅۽ ਃࣗܳ ଺ਸ ࣻ ੓׮. • By.depth(int depth) • By.hasChild(BySelector childSelector) • By.hasDescendant(BySelector descendantSelector) • By.hasDescendant(BySelector descendantSelector, int maxDepth)
  21. ӝ ӝ ઑ ੘ ೞ ӝ H A N D

    L I N G D E V I C E UiDevice ઱ਃ ݫࣗ٘ • click(int x, int y) • drag(int startX, int startY, int endX, int endY, int steps) • openNotification() • openQuickSettings() • pressBack() • pressDelete() • pressEnter() • pressHome() • pressKeyCode(int keyCode) • pressKeyCode(int keyCode, int metaState) • pressMenu() • pressRecentApps() • pressSearch() • setOrientationLeft() • setOrientationNatural() • setOrientationRight() • swipe(int startX, int startY, int endX, int endY, int steps) • swipe(Point[] segments, int segmentSteps) • takeScreenshot(File storePath, float scale, int quality) • takeScreenshot(File storePath) • wakeUp()
  22. U I ਃ ࣗ ઑ ੘ ೞ ӝ H A

    N D L I N G U I E L E M E N T S UiObject2 ઱ਃ ݫࣗ٘ • click() • click(long duration) • clickAndWait(EventCondition<R> condition, long timeout) • drag(Point dest) • drag(Point dest, int speed) • fling(Direction direction, int speed) • fling(Direction direction) • longClick() • pinchClose(float percent) • pinchClose(float percent, int speed) • pinchOpen(float percent) • pinchOpen(float percent, int speed) • scroll(Direction direction, float percent, int speed) • scroll(Direction direction, float percent) • setText(String text) • swipe(Direction direction, float percent, int speed) • swipe(Direction direction, float percent)
  23. ೾ ಌ ݫ ࣗ ٘ 1 H E L P

    E R M E T H O D S 1 // BaseTest.java
 protected UiObject2 findButton(int textResourceId) { // textResourceIdо ಴दػ ߡౡਸ ଺ח׮.
 return findObject(button(textResourceId));
 } 
 protected BySelector button(int textResourceId) { // textResourceIdо ಴दػ ߡౡਸ աఋղח BySelector.
 return By.text(string(textResourceId)).clickable(true);
 } 
 protected UiObject2 findByText(int textResourceId) { // textResourceIdо ಴दػ ਃࣗܳ ଺ח׮.
 return findObject(byText(textResourceId));
 } 
 protected BySelector byText(int textResourceId) { // textResourceIdо ಴दػ ਃࣗܳ աఋղח BySelector.
 return By.text(string(textResourceId));
 }
  24. ೾ ಌ ݫ ࣗ ٘ 1 H E L P

    E R M E T H O D S 1 // BaseTest.java
 protected UiObject2 findButton(int textResourceId) { // textResourceIdо ಴दػ ߡౡਸ ଺ח׮.
 return findObject(button(textResourceId));
 } 
 protected BySelector button(int textResourceId) { // textResourceIdо ಴दػ ߡౡਸ աఋղח BySelector.
 return By.text(string(textResourceId)).clickable(true);
 } 
 protected UiObject2 findByText(int textResourceId) { // textResourceIdо ಴दػ ਃࣗܳ ଺ח׮.
 return findObject(byText(textResourceId));
 } 
 protected BySelector byText(int textResourceId) { // textResourceIdо ಴दػ ਃࣗܳ աఋղח BySelector.
 return By.text(string(textResourceId));
 }
  25. ೾ ಌ ݫ ࣗ ٘ 2 H E L P

    E R M E T H O D S 2 // BaseTest.java protected UiObject2 findByDesc(int textResourceId) { // textResourceIdܳ ஶబ౟ ࢸݺਵ۽ ыח ਃࣗܳ ଺ח׮.
 return findObject(byDesc(textResourceId));
 }
 
 protected BySelector byDesc(int textResourceId) { // textResourceIdܳ ஶబ౟ ࢸݺਵ۽ ыח BySelector.
 return By.desc(string(textResourceId));
 }
 
 protected String string(int textResourceId) { // textResourceIdী ೧׼ೞח ޙ੗ৌ.
 return getTargetContext().getString(textResourceId);
 } protected UiObject2 findObject(BySelector selector) {
 mDevice.wait(Until.hasObject(selector), DEFAULT_TIMEOUT);
 return mDevice.findObject(selector);
 }
  26. ೾ ಌ ݫ ࣗ ٘ 2 H E L P

    E R M E T H O D S 2 // BaseTest.java protected UiObject2 findByDesc(int textResourceId) { // textResourceIdܳ ஶబ౟ ࢸݺਵ۽ ыח ਃࣗܳ ଺ח׮.
 return findObject(byDesc(textResourceId));
 }
 
 protected BySelector byDesc(int textResourceId) { // textResourceIdܳ ஶబ౟ ࢸݺਵ۽ ыח BySelector.
 return By.desc(string(textResourceId));
 }
 
 protected String string(int textResourceId) { // textResourceIdী ೧׼ೞח ޙ੗ৌ.
 return getTargetContext().getString(textResourceId);
 } protected UiObject2 findObject(BySelector selector) {
 mDevice.wait(Until.hasObject(selector), DEFAULT_TIMEOUT);
 return mDevice.findObject(selector);
 }
  27. ೾ ಌ ݫ ࣗ ٘ 2 H E L P

    E R M E T H O D S 2 // BaseTest.java protected UiObject2 findByDesc(int textResourceId) { // textResourceIdܳ ஶబ౟ ࢸݺਵ۽ ыח ਃࣗܳ ଺ח׮.
 return findObject(byDesc(textResourceId));
 }
 
 protected BySelector byDesc(int textResourceId) { // textResourceIdܳ ஶబ౟ ࢸݺਵ۽ ыח BySelector.
 return By.desc(string(textResourceId));
 }
 
 protected String string(int textResourceId) { // textResourceIdী ೧׼ೞח ޙ੗ৌ.
 return getTargetContext().getString(textResourceId);
 } protected UiObject2 findObject(BySelector selector) {
 mDevice.wait(Until.hasObject(selector), DEFAULT_TIMEOUT);
 return mDevice.findObject(selector);
 }
  28. ೾ ಌ ݫ ࣗ ٘ 3 H E L P

    E R M E T H O D S 3 // BaseTest.java
 protected void hideKeyboard() {
 InputMethodManager manager = (InputMethodManager) getTargetContext()
 .getSystemService(Context.INPUT_METHOD_SERVICE);
 if (manager.isAcceptingText()) {
 mDevice.pressBack();
 }
 } protected void assertHas(BySelector selector) {
 assertTrue(mDevice.hasObject(selector));
 }
  29. ೾ ಌ ݫ ࣗ ٘ 3 H E L P

    E R M E T H O D S 3 // BaseTest.java
 protected void hideKeyboard() {
 InputMethodManager manager = (InputMethodManager) getTargetContext()
 .getSystemService(Context.INPUT_METHOD_SERVICE);
 if (manager.isAcceptingText()) {
 mDevice.pressBack();
 }
 } protected void assertHas(BySelector selector) {
 assertTrue(mDevice.hasObject(selector));
 }
  30. U I ప झ ౟ ੘ ࢿ ೞ ӝ W

    R I T I N G U I T E S T S
  31. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T public class MainActivityTest extends BaseTest {
 @Before
 @Override
 public void before() throws IOException { Session.setAccessToken(null);
 super.before();
 }
 
 @Test
 public void testPressBack() {
 mDevice.pressBack();
 assertFalse(mDevice.hasObject(By.pkg(BuildConfig.APPLICATION_ID)));
 }
 }
  32. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T public class MainActivityTest extends BaseTest {
 @Before
 @Override
 public void before() throws IOException { Session.setAccessToken(null);
 super.before();
 }
 
 @Test
 public void testPressBack() {
 mDevice.pressBack();
 assertFalse(mDevice.hasObject(By.pkg(BuildConfig.APPLICATION_ID)));
 }
 }
  33. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T // BaseTest.java @RunWith(AndroidJUnit4.class)
 public abstract class BaseTest {
 protected UiDevice mDevice;
 
 @Before
 public void before() {
 mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 assertNotNull(mDevice);
 openApp();
 }
 }
  34. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T // strings.xml <string name="sign_up_as_a_pro">Ҋࣻ۽ оੑ</string> <string name=“start”>द੘ೞӝ</string> // MainActivityTest.java @Test
 public void testSignUpAsAProButton() {
 findButton(R.string.sign_up_as_a_pro) .clickAndWait(Until.newWindow(), DEFAULT_TIMEOUT);
 assertHas(button(R.string.start));
 } 
 private void assertInProSignUpActivity() {
 assertHas(button(R.string.start));
 }
  35. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T // strings.xml <string name="sign_up_as_a_pro">Ҋࣻ۽ оੑ</string> <string name=“start”>द੘ೞӝ</string> // MainActivityTest.java @Test
 public void testSignUpAsAProButton() {
 findButton(R.string.sign_up_as_a_pro) .clickAndWait(Until.newWindow(), DEFAULT_TIMEOUT);
 assertHas(button(R.string.start));
 } 
 private void assertInProSignUpActivity() {
 assertHas(button(R.string.start));
 }
  36. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T // strings.xml <string name=“sign_up_as_a_user">ਃ୒੗۽ оੑ</string> <string name=“sign_up”>ഥਗоੑ</string> <string name=“sign_up_with_facebook”>ಕ੉झ࠘ਵ۽ ഥਗоੑ</string> // MainActivityTest.java @Test
 public void testSignUpAsAUserButton() {
 findButton(R.string.sign_up_as_a_user) .clickAndWait(Until.newWindow(), DEFAULT_TIMEOUT); hideKeyboard();
 assertInUserSignUpActivity();
 } private void assertInUserSignUpActivity() {
 assertHas(byText(R.string.sign_up));
 assertHas(byText(R.string.sign_up_with_facebook));
 }
  37. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T // strings.xml <string name=“sign_up_as_a_user">ਃ୒੗۽ оੑ</string> <string name=“sign_up”>ഥਗоੑ</string> <string name=“sign_up_with_facebook”>ಕ੉झ࠘ਵ۽ ഥਗоੑ</string> // MainActivityTest.java @Test
 public void testSignUpAsAUserButton() {
 findButton(R.string.sign_up_as_a_user) .clickAndWait(Until.newWindow(), DEFAULT_TIMEOUT); hideKeyboard();
 assertInUserSignUpActivity();
 } private void assertInUserSignUpActivity() {
 assertHas(byText(R.string.sign_up));
 assertHas(byText(R.string.sign_up_with_facebook));
 }
  38. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T // strings.xml <string name=“sign_in”>۽Ӓੋ</string> <string name=“sign_in_with_facebook”>ಕ੉झ࠘ਵ۽ ۽Ӓੋೞӝ</string> // MainActivityTest.java @Test
 public void testSignInButton() {
 findButton(R.string.sign_in) .clickAndWait(Until.newWindow(), DEFAULT_TIMEOUT);
 assertInSignInActivity();
 } 
 private void assertInSignInActivity() {
 assertHas(byText(R.string.sign_in));
 assertHas(byText(R.string.sign_in_with_facebook));
 }
  39. ୐ ߣ ૩ ప झ ౟ O U R F

    I R S T T E S T // strings.xml <string name=“sign_in”>۽Ӓੋ</string> <string name=“sign_in_with_facebook”>ಕ੉झ࠘ਵ۽ ۽Ӓੋೞӝ</string> // MainActivityTest.java @Test
 public void testSignInButton() {
 findButton(R.string.sign_in) .clickAndWait(Until.newWindow(), DEFAULT_TIMEOUT);
 assertInSignInActivity();
 } 
 private void assertInSignInActivity() {
 assertHas(byText(R.string.sign_in));
 assertHas(byText(R.string.sign_in_with_facebook));
 }
  40. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N UI ਃࣗח ࠺زӝ੸ਵ۽ ੘زೞ޲۽, زӝചܳ ೧઱૑ ঋਵݶ పझ౟о पಁೠ׮. ୐ߣ૩ ߑߨਵ۽, EventConditionਸ ഝਊೞৈ ౠ੿ ੉߮౟о ੌযաӝө૑ ӝ׮ܽ׮. • UiObject2#clickAndWait(EventCondition<R> condition, long timeout)
 UiObject2ܳ௿ܼೞҊconditionਸ݅઒ೡٸө૑ӝ׮ܽ׮ • UiDevice#performActionAndWait(Runnable action, EventCondition<R> condition, long timeout)
 actionਸ ࣻ೯ೞҊ conditionਸ ݅઒ೡ ٸө૑ ӝ׮ܽ׮. ex) findButton(R.string.sign_up_as_a_pro).clickAndWait(Until.newWindow(), DEFAULT_TIMEOUT); mDevice.performActionAndWait(() -> {
 findButton(R.string.sign_up_as_a_pro).click();
 }, Until.newWindow(), DEFAULT_TIMEOUT);
  41. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ӝࠄ ઁҕغח EventCondition਷ Until.newWindow()৬ Until.scrollFinished()о ੓׮. • Until.newWindow()
 ࢜۽਍ ହ(Activity ഑਷ Dialog)੉ ࢤࢿعח૑ ৈࠗ. • Until.scrollFinished(final Direction direction)
 direction ߑೱਵ۽ झ௼܀੉ ՘լח૑ ৈࠗ.
  42. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ழझథ ੉߮౟ ઑѤਸ ਤ೧ࢲח EventConditionਸ ࢲ࠳௿ېयೞݶ ػ׮. public abstract class EventCondition<R> extends Condition<AccessibilityEvent, Boolean> {
 abstract Boolean apply(AccessibilityEvent event);
 
 abstract R getResult();
 }
  43. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ੉ ৻ী ചݶী UI ਃࣗо ੓ח૑ ӝ׮ܻ۰ݶ SearchConditionਸ ࢎਊೞݶ ػ׮. • UiDevice#wait(SearchCondition<R> condition, long timeout)
 ചݶীࢲ condition੉ ࢿ݀ؼ ٸө૑ ӝ׮ܽ׮.
 • UiObject2#wait(SearchCondition<R> condition, long timeout)
 ೧׼ UiObject2 ё୓ ղীࢲ condition੉ ࢿ݀ؼ ⮶ө૑ ӝ׮ܽ׮. ex) mDevice.wait(Until.hasObject(By.scrolllable(true)), DEFAULT_TIMEOUT); findObject(By.scrollable(true)).wait(Until.hasObject(By.clickable(true)), DEFAULT_TIMEOUT);
  44. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ӝࠄ ઁҕغח SearchCondition • Until.gone(final BySelector selector)
 selectorী ೧׼ೞח ਃࣗо ࢎۄ઎ח૑ ৈࠗ.
 • Until.hasObject(final BySelector selector)
 selectorী ೧׼ೞח ਃࣗо ߊѼ೮ח૑ ৈࠗ. ߊѼ ৈࠗܳ ܻఢೠ׮.
 • Until.findObject(final BySelector selector)
 selectorী ೧׼ೞח ਃࣗܳ ߊѼ೮ח૑ ৈࠗ. ߊѼೠ ਃࣗܳ ܻఢೠ׮. • Until.findObjects(final BySelector selector)
 selectorী ೧׼ೞח ਃࣗܳ ߊѼ೮ח૑ ৈࠗ. ߊѼೠ ৈ۞ѐ੄ ਃࣗܳ ܻఢೠ׮.
  45. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ழझథ Ѩ࢝ ઑѤਸ ਤ೧ࢲח SearchConditionਸ ࢲ࠳௿ېयೞݶ ػ׮. public abstract class SearchCondition<R> extends Condition<Searchable, R> {
 }
  46. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ݃૑݄ਵ۽ UiObject2 ё୓੄ ࢚కо ઑѤਸ ݅઒ೞӝܳ ӝ׮ܻ۰ݶ UiObject2Conditionܳ ࢎਊೞݶ ػ׮. • UiObject2#wait(UiObject2Condition<R> condition, long timeout)
 UiObject2੄ ࢚కо conditionҗ ੌ஖ೡ ٸө૑ ӝ׮ܽ׮. ex) findByDesc(R.string.check_box).wait(Until.selected(true), DEFAULT_TIMEOUT);
  47. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ӝࠄ ઁҕغח UiObject2Condition •Until.checkable() •Until.checked() •Until.clickable() •Until.enabled() •Until.focusable() •Until.focused() •Until.longClickable() •Until.scrollable() •Until.selected() •Until.descMatches() •Until.descEquals() •Until.descContains() •Until.descStartsWith() •Until.descEndsWith() •Until.textMatches() •Until.textNotEquals() •Until.textEquals() •Until.textContains() •Until.textStartsWith() •Until.textEndsWith()
  48. U I ز ӝ ച U I S Y N

    C H R O N I Z A T I O N ழझథ UiObject2 ࢚క ઑѤਸ ਤ೧ࢲח UiObject2Conditionਸ ࢲ࠳௿ېयೞݶ ػ׮. public abstract class UiObject2Condition<R> extends Condition<UiObject2, R> {
 }
  49. গ פ ݫ ੉ ࣌ ࠺ ഝ ࢿ ച D

    I S A B L I N G A N I M A T I O N S গפݫ੉࣌ਵ۽ ੋೠ పझ౟ पಁܳ ߑ૑ೞӝ ਤ೧ ࠺ഝࢿച ೧઱যঠ ೠ׮. // AndroidManifest.xml
 <uses-permission android:name=“android.permission.SET_ANIMATION_SCALE"/> // app/build.gradle task grantAnimationPermission(type: Exec, dependsOn: 'installDebug') {
 commandLine "adb shell pm grant com.soomgo android.permission.SET_ANIMATION_SCALE".split(' ')
 }
 
 tasks.whenTaskAdded { task ->
 if (task.name.startsWith('connected')) {
 task.dependsOn grantAnimationPermission
 }
 }
  50. গ פ ݫ ੉ ࣌ ࠺ ഝ ࢿ ച D

    I S A B L I N G A N I M A T I O N S গפݫ੉࣌ਵ۽ ੋೠ పझ౟ पಁܳ ߑ૑ೞӝ ਤ೧ ࠺ഝࢿച ೧઱যঠ ೠ׮. // AndroidManifest.xml
 <uses-permission android:name=“android.permission.SET_ANIMATION_SCALE"/> // app/build.gradle task grantAnimationPermission(type: Exec, dependsOn: 'installDebug') {
 commandLine "adb shell pm grant com.soomgo android.permission.SET_ANIMATION_SCALE".split(' ')
 }
 
 tasks.whenTaskAdded { task ->
 if (task.name.startsWith('connected')) {
 task.dependsOn grantAnimationPermission
 }
 }
  51. গ פ ݫ ੉ ࣌ ࠺ ഝ ࢿ ച D

    I S A B L I N G A N I M A T I O N S // BaseTest.java @Before
 public void before() throws IOException {
 ...
 mSystemAnimations = new SystemAnimations(getTargetContext());
 mSystemAnimations.disableAll();
 }
 
 @After
 public void after() {
 if (mSystemAnimations != null) {
 mSystemAnimations.enableAll();
 }
 }
  52. ௿ ۄ ਋ ٘ ೒ ۖ ಬ C L O

    U D P L A T F O R M S AWS Device Farm Firebase Test Lab Xamarin Test Cloud 200+ ӝӝ $0.17/࠙ Appium, Calabash, Instrumentation, UI Automator, Explorer ૑ਗ 20+ ӝӝ $5/दр Instrumentation, Robo పझ౟ ૑ਗ 1000+ ӝӝ ୭ࣗ $99/׳ Calabash(Ruby), Xamarin UITest(C#)
  53. AWS ҅੿ ࢤࢿ https://aws.amazon.com/ AWS ௑ࣛ ੽ࣘ https://console.aws.amazon.com/devicefarm ೐۽ં౟ ࢤࢿ

    ‘Create a new project’ ࢜۽਍ పझ౟ ࢤࢿ ‘Create a new run’ 1 2 3 4 द ੘ ೞ ӝ G E T T I N G S T A R T E D
  54. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D 1ױ҅ীࢲ উ٘۽੉٘ ೒ۖಬ ࢶఖ റ জ प೯ apk ౵ੌ স۽٘. ‘Run name’ী పझ౟ ੉ܴ ੑ۱.
  55. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D 2ױ҅ীࢲ ‘Instrumentation’ ࢶఖ. (UI Automatorо ইש) ./gradlew assembleAndroidTest : పझ౟ apk ࢤࢿ. “app/build/outputs/apk”੄ పझ౟ apk স۽٘.
  56. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D 3ױ҅ীࢲ పझ౟ܳ ਗೞח ఋѶ ٣߄੉झ ࢶఖ. Device Poolਸ ࢤࢿ೧֬ਵݶ ੤ഝਊ оמ.
  57. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D 4ױ҅ীࢲ ਗೞח ٣߄੉झ ࢚క ࢸ੿.
  58. द ੘ ೞ ӝ G E T T I N

    G S T A R T E D 5ױ҅ীࢲ ఋ੐ইਓ ࢸ੿(۽ஸীࢲ ஏ੿чী ডр੄ ৈਬчਸ ؊೧ࢲ). పझ౟ प೯.
  59. х ࢎ ೤ פ ׮ C O N T A

    C T M E % & LINKEDIN.COM/IN/YOONJAEYOO FACEBOOK.COM/RYUNZAE [email protected] 010-9525-1659 ' (