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

QA엔지니어가 바라본 모바일 자동화 테스트

kakao
December 09, 2022

QA엔지니어가 바라본 모바일 자동화 테스트

#QA #Test #MobileAutomation #E2ETestAutomation

카카오페이 QA팀에서 모바일 자동화 테스트를 통해 얻은 다양한 경험들을, 적용한 사례와 함께 공유합니다.

발표자 : ellie.yun
카카오페이 QA팀에서 자동화 테스트 업무를 담당하고 있는 ellie입니다.

kakao

December 09, 2022
Tweet

More Decks by kakao

Other Decks in Programming

Transcript

  1. 윤지혜 Ellie.Yun 카카오페이 모바일 자동화 테스트 사례와 경험 공유 QA

    엔지니어가 바라본 모바일 자동화 테스트 Copyright 2022. Kakao Corp. All rights reserved. Redistribution or public display is not permitted without written permission from Kakao. if(kakao)2022
  2. - Test Environment • Multi Device • Cross Platform -

    Test Design • Layer Strategy #1. Maintenance
  3. iOS Appium UI Automator Test Code Systemport 8200 8201 8202

    Session Appium XCUI Test Test Code Session wdaLocalPort 8100 8101 Android Multi Device | #1. maintenance Android 8102 Android Android
  4. | #1. maintenance iOS Appium UI Automator XCUI Test Android

    Test Code Maintenance Cross Platform Systemport 8200 8201 8202 Android Android Android wdaLocalPort 8100 8101 8102 Session
  5. Control 
 Layer User Action Test Layer TestCase Business Layer

    Service Layer Strategy | #1. maintenance
  6. Control 
 Layer User Action Test Layer TestCase Business Layer

    Service Layer Strategy | #1. maintenance
  7. public void click(MobileElement e, String msg){ waitForClickability(e); e.click(); pringLog("[Step] "

    + msg); } public void sendKeys(MobileElement e, String txt, String msg) { waitForVisibility(e); e.clear(); e.sendKeys(txt); pringLog("[Step] " + msg); } public void waitForVisibility(MobileElement e, long timeout) { wait = new WebDriverWait(driver, timeout); wait.ignoring(StaleElementReferenceException.class); wait.until(ExpectedConditions.visibilityOf(e)); } public void scrollToElement(String target, ScrollType scrollType, String msg) { WebElement webElement = base.getDriver().findElement(target); HashMap<String, String> scrollObject = new HashMap<>(); scrollObject.put("element", webElement.getId()); scrollObject.put("direction", scrollType.getName()); base.getDriver().executeScript("mobile:scroll", scrollObject); return(MobileElement) webElement; }
  8. Control 
 Layer User Action Test Layer TestCase Business Layer

    Service Layer Strategy | #1. maintenance
  9. Business layer = Business logic Step 1. Business unit Business

    unit을 식별, Unit별로 클래스 생성 Element initialization Step 2. Application map Element initialization + Control layer = Business logic Step 3. Business map Business Layer
  10. Business fl ow: 친구에게 송금하기 1. 친구를 클릭한다. 2. 송금

    금액을 입력한다. 3. 확인 버튼을 클릭한다. 4. 송금 버튼을 클릭한다. Business Layer
  11. Business Layer Business fl ow: 친구에게 송금하기 1. 친구를 클릭한다.

    2. 송금 금액을 입력한다. 3. 확인 버튼을 클릭한다. 4. 송금 버튼을 클릭한다.
  12. Business fl ow: 친구에게 송금하기 1. 친구를 클릭한다. 2. 송금

    금액을 입력한다. 3. 확인 버튼을 클릭한다. 4. 송금 버튼을 클릭한다. Business Layer
  13. Business fl ow: 친구에게 송금하기 1. 친구를 클릭한다. 2. 송금

    금액을 입력한다. 3. 확인 버튼을 클릭한다. 4. 송금 버튼을 클릭한다. Business Layer
  14. Step 1. Business Unit을 식별하여 클래스 생성 Business Layer -

    친구송금의 business unit은 송금 (remittance) ChargePage.java RemittancePage.java BankAccountRegisterPage.java SprinkleMoneyPage.java
  15. Step 2. Element Initialization public class RemittancePage extends BasePage {

    @AndroidFindBy(id = "pay_money_amount_edit") @iOSFindBy(iOSClassChain = "**/XCUIElementTypeCell[`label==\"ࠁյӘঘ(ਗ)\"`]") private MobileEment remittanceAmountField; @AndroidFindBy(id = "pay_money_send_confirm") @iOSFindBy(iOSClassChain = "**/XCUIElementTypeCell[`label CONTAINS \"ࠁղӝ\"`]") private MobileEment remittanceSendBtn; @AndroidFindBy(id = "btn_confirm") @iOSFindBy(accessibility = "ഛੋ") private MobileEment confirmBtn; public RemittancePage(AppiumDriver<MobileEment> driver){ super(driver); PageFactory.initElements(new AppiumFieldDecorator(driver), this); } ... } Business Layer 송금 금액 송금 버튼
  16. Step 3. Business Logic Business Layer 친구를 클릭한다. 송금 금액을

    입력한다. 확인 버튼을 클릭한다. click send text wait visibility scroll Control Layer remittanceAmountField remittanceSendBtn con fi rmBtn Element Business Logic X 송금 버튼을 클릭한다.
  17. Step 3. Business Logic Business Layer 친구를 클릭한다. 송금 금액을

    입력한다. 확인 버튼을 클릭한다. click send text wait visibility scroll Control Layer remittanceAmountField remittanceSendBtn con fi rmBtn Element Business Logic X 송금 버튼을 클릭한다.
  18. Step 3. Business Logic public RemittancePage remittanceRequest(RemittanceReqDto remittanceReqDto) { chooseRemittanceReceiver(remittanceReqDto);

    fillInAmount(remittanceReqDto); pressMoneySend(); ... } public RemittancePage fillInAmount(RemittanceReqDto remittanceReqDto) { sendKeys(remittanceAmountField, remittanceReqDto.getRemittanceAmount(), “࣠Ә Әঘ ੑ۱”); ... click(confirmBtn, “ഛੋ ߡౡ ௿ܼ"); } public RemittancePage pressMoneySend() { click(remittanceSendBtn, “࣠Ә ߡౡ ௿ܼ"); ... } Business Layer
  19. Control 
 Layer User Action Test Layer TestCase Business Layer

    Service Layer Strategy | #1. maintenance
  20. 송금 타입 송금 대상 송금 금액 봉투사용 여부 충전 계좌

    RemittanceReqDTO 수수료 여부 송금 타입 송금 대상 송금 금액 봉투사용 여부 충전 계좌 Test Layer
  21. TestCase #01. 친구에게 송금한다. TestCase #02. 친구에게 봉투 송금한다. TestCase

    #03. 친구에게 보유잔액을 초과한 금액을 현재 계좌에서 충전하여 송금한다. TestCase #04. 상대방 계좌로 송금한다. TestCase #05. 상대방 계좌로 보유잔액을 초과한 금액을 부계좌에서 충전하여 송금한다. Test Layer 친구 계좌 잔액 잔액초과 일반 봉투 변경 유지 충전 계좌 송금 형태 송금 금액 송금 구분
  22. TestCase #01. 친구에게 송금한다. TestCase #02. 친구에게 봉투 송금한다. TestCase

    #03. 친구에게 보유잔액을 초과한 금액을 현재 계좌에서 충전하여 송금한다. TestCase #04. 상대방 계좌로 송금한다. TestCase #05. 상대방 계좌로 보유잔액을 초과한 금액을 부계좌에서 충전하여 송금한다. Test Layer 일반 봉투 친구 계좌 잔액 잔액초과 변경 유지 충전 계좌 송금 형태 송금 금액 송금 구분
  23. TestCase #01. 친구에게 송금한다. TestCase #02. 친구에게 봉투 송금한다. TestCase

    #03. 친구에게 보유잔액을 초과한 금액을 현재 계좌에서 충전하여 송금한다. TestCase #04. 상대방 계좌로 송금한다. TestCase #05. 상대방 계좌로 보유잔액을 초과한 금액을 부계좌에서 충전하여 송금한다. Test Layer 잔액 잔액초과 송금 금액 친구 계좌 일반 봉투 변경 유지 충전 계좌 송금 형태 송금 구분
  24. TestCase #01. 친구에게 송금한다. TestCase #02. 친구에게 봉투 송금한다. TestCase

    #03. 친구에게 보유잔액을 초과한 금액을 현재 계좌에서 충전하여 송금한다. TestCase #04. 상대방 계좌로 송금한다. TestCase #05. 상대방 계좌로 보유잔액을 초과한 금액을 부계좌에서 충전하여 송금한다. Test Layer 친구 계좌 송금 구분 잔액 잔액초과 일반 봉투 변경 유지 충전 계좌 송금 형태 송금 금액
  25. TestCase #01. 친구에게 송금한다. TestCase #02. 친구에게 봉투 송금한다. TestCase

    #03. 친구에게 보유잔액을 초과한 금액을 현재 계좌에서 충전하여 송금한다. TestCase #04. 상대방 계좌로 송금한다. TestCase #05. 상대방 계좌로 보유잔액을 초과한 금액을 부계좌에서 충전하여 송금한다. Test Layer 변경 유지 충전 계좌 친구 계좌 송금 구분 일반 봉투 송금 형태 잔액 잔액초과 송금 금액
  26. public void TC002_friendRemittance_withEnvelop() { remittanceReqDto = RemittanceReqDto.builder() .transactionType(TransactionType.FRIEND_REMITTANCE) .withEnvelop(True) .txAmount(moneyData.getTransactionAmount())

    .bankAccount(primaryBankAccount) .receiver(moneyTarget.getTalkReceiver()) .build(); remittancePage .remittanceRequest(remittanceReqDto); resDto = remittancePage.getRemittanceResDtoOnPass(remittanceReqDto); assertThat(resDto.getResultTitle(), is(equalTo(Money.Remittance.COMPLETE))); assertThat(resDto.getResultAmount(), is(equalTo(remittancePage.getTxAmount())); ... } Test Layer 송금구분 : 친구송금 송금형태 : 봉투송금 송금금액 : 잔액 내 충전계좌 : 유지 (기본계좌) Test data set 전달
  27. Control 
 Layer User Action Test Layer TestCase 확장성 Business

    Layer 비즈니스 흐름에 집중 Layer Strategy | #1. maintenance
  28. - Log - Report - Open Search - Grafana -

    DeviceFarm #2. Monitoring
  29. Log TestSuite TestCase 1 TestCase 2 Step Assertion PreCondition Navigation

    Step Assertion PreCondition Navigation | #2. monitoring Device Log Device Report Appium Server Log
  30. | #3. process 서비스 QA 자동화 QA 요구사항 전달 과제

    리뷰 자동화 테스트케이스 작성 테스트 계획 자동화 테스트 코드 구현 테스트 타당성 조사 데일리 리포트 운영 모니터링 신규기능 유지보수 전체 프로세스
  31. 서비스 QA 자동화 QA 요구사항 전달 과제 리뷰 자동화 테스트케이스

    작성 테스트 계획 자동화 테스트 코드 구현 테스트 타당성 조사 데일리 리포트 운영 모니터링 신규기능 유지보수 신규기능 프로세스 | #3. process
  32. 서비스 QA 자동화 QA 요구사항 전달 과제 리뷰 자동화 테스트케이스

    작성 테스트 계획 자동화 테스트 코드 구현 테스트 타당성 조사 데일리 리포트 운영 모니터링 신규기능 유지보수 유지보수 프로세스 | #3. process
  33. | #3. process 서비스 QA 자동화 QA 요구사항 전달 과제

    리뷰 자동화 테스트케이스 작성 테스트 계획 자동화 테스트 코드 구현 테스트 타당성 조사 데일리 리포트 운영 모니터링 신규기능 유지보수 운영 모니터링 프로세스
  34. | #3. process Jenkins DeviceFarm 테스트 Hook 알림 결함 여부

    파악 애플리케이션 오류 및 내부 이슈인 경우 담당자 태그 처리 데일리 리포트 최종 리포트 공유 운영 모니터링 시작 에러 발생 정상 완료 운영 모니터링 상세 프로세스
  35. - Test Failure Handling • Recovery • Manage Dependency Between

    TestCases - Effective Locator Strategies - Performance Improvement Studies 고민했던 것들
  36. TestCase 1 TestSuite 친구송금 TestCase 2 TestCase 3 케이스 실행

    도중 실패되었다면 다음 케이스 실행에 영향이 없을까요? Recovery | Test failure handling
  37. FAIL 현재 화면과 예상 화면이 다르다. 이 상세 스텝에서 실패되었다면?

    TestSuite 친구송금 TestCase 1 Step 3. 송금하기 Step1. 더보기 > 페이홈 > 송금 화면 이동 Step 2. 송금 금액 입력 Step 4. 송금 화면 > 페이홈 화면으로 이동 Step 3~Step 4는 동작하지 않을 것이다. TestCase 2 Step 1. 페이홈 > 송금 화면 이동 Step 2. 송금 금액 입력 Step 3. 봉투 송금하기 Step 4. 송금 화면 > 페이홈 화면으로 이동 이후 케이스가 모두 실패될 것이다. Recovery | Test failure handling
  38. Recovery | Test failure handling Fail 발생 Test Listener 감지

    Next TestCase 실행 Log 추출 Fail Image 캡처 Recovery process 1. Terminate App 2. Activate App 3. PostCondition Navigation TestSuite별 사전 정의된 시작 화면으로 랜딩
  39. | Test failure handling - TC001: 친구송금 케이스 - TC002:

    송금 내역 확인 케이스 @Test(groups = {TEST, PRODUCTION}) public void TC001_xxx() {…} @Test(groups = {TEST, PRODUCTION}, dependsOnMethods={“TC001_xxx”}) public void TC002_xxx() {…} @Test(groups = {TEST, PRODUCTION}) public void TC003_xxx() {…} Manage Dependency Between TestCases
  40. | Test failure handling TestCase 1 TestSuite 친구송금 TestCase 2

    TestCase 3 FAIL PASS 케이스 실행 도중 실패되었다면? SKIP Manage Dependency Between TestCases
  41. 테스트 코드 성능(실행 속도), 안정성(엘리먼트 변경에 의한 테스트 실패)을 높이기

    위한 locator 전략 1. 속도 비교 2. well - made locator (최적화된 locator) 3. 동적 locator1) 사용 4. 신규 locator 연구 및 적용 Effective Locator Strategies 1) w3schools, “XPath”, 2020년 5월 25일, https:/ /www.w3schools.com/xml/xpath_axes.asp
  42. - 동적 locator Xpath Axes 예시 설명 ancestor 현재 노드의

    모든 조상 노드를 선택합니다. (부모 및 조상 노드) parent 현재 노드의 모든 부모 노드를 선택합니다. child 현재 노드의 모든 자식을 선택합니다. descendant 현재 노드의 모든 후손을 선택합니다. following - sibling 현재 노드 다음에 오는 모든 형제 노드를 선택합니다. preceding - sibling 현재 노드 이전의 모든 형제 노드를 선택합니다. Effective Locator Strategies
  43. - 동적 locator • 우측 그림에 보이는 수수료 금액 “무료”를

    체크한다고 가정 • full xpath 사용하는 경우 Xpath = "/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/ android.widget.FrameLayout/android.widget.FrameLayout/ android.widget.FrameLayout/android.widget.FrameLayout/android.view.ViewGroup/ android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout/ android.view.ViewGroup/android.widget.ScrollView/android.widget.FrameLayout/ android.view.ViewGroup/android.widget.LinearLayout/android.view.ViewGroup[3]/ android.widget.TextView[2]" Effective Locator Strategies
  44. Effective Locator Strategies - 동적 locator • 상대 경로 사용하는

    경우 Xpath = “//android.widget.FrameLayout/android.view.ViewGroup/android.widget.LinearLayout/ android.view.ViewGroup[3]/android.widget.TextView[2]" Xpath = "//android.widget.TextView[@text = \"ࣻࣻܐ\"]/../android.widget.TextView[2]"
  45. Effective Locator Strategies - 신규 locator 연구 및 적용 •

    iOS Class chain2) Predicate3) Locator 예시 Class chain **/XCUIElementTypeOther[`label == \"즉시할인 미적용\" AND value == \"1\"`][1] **/XCUIElementTypeOther[`name BEGINSWITH “순차결제"`] Predicate label == \"보내기\" AND name == \"보내기\" AND value == \"1\" AND visible ==true 2) Meta Archive Github, “WebDriverAgent”, 2020년 5일 25일, https:/ /github.com/facebookarchive/WebDriverAgent/wiki/Class - Chain - Queries - Construction - Rules 3) Meta Archive Github, “WebDriverAgent”, 2020년 5월 25일, https:/ /github.com/facebookarchive/WebDriverAgent/wiki/Predicate - Queries - Construction - Rules
  46. - Wait 테스트 • WebDriverWait & FluentWait & AppiumFluentWait •

    Implicit wait & Explicit wait - iOS 성능개선 방안에 따른 적용 테스트 Performance Improvement Studies
  47. - WebDriverWait & FluentWait & AppiumFluentWait - 배경: • 전체적인

    테스트 소요시간이 너무 많이 소요 • wait에서의 대기시간을 줄여보자 - 결과: • 모두 polling 주기 설정이 가능 • 기본 조건 셋팅으로는 성능상의 차이가 없다. • AppiumFluentWait 의 Polling 전략을 사용하면 유연하게 제어할 수 있다. Performance improvement studies 조건 시나리오 기대 결과 polling: 500ms / timeout: 10s 기본값에서 wait 조건 체크 시간 테스트 동일 (500ms 마다 체크 후 10s timeout) polling: 100ms / timeout: 10s Polling 주기를 줄인 경우 wait 시 조건 체크 시간 테스트 100ms 주기로 기본값보다 빠르게 체크 polling: 500ms / timeout: 10s / .withPollingStrategy(조건) Polling Strategy을 설정하여 polling 주기를 조정 Timeout 시간내 점점 더 느리게/빠르게 polling 설정 가능
  48. Performance Improvement Studies - Implicit wait & Explicit wait -

    배경: • 화면 전환 시 로딩이 느린 이슈 • Explicit Wait의 timeout 시간이 기대보다 더 걸리는 이슈 - 결과: • Implicit Wait만 사용한 경우, 5초로 기대한 시간과 동일 • Timeout 시간이 설정한 시간보다 1~5초 더 발생 • Explicit Wait의 timeout값은 Implicit Wait보다 커야함 조건 시나리오 기대 결과 isElementPresentWithTimeoutTest() 7, 15, 20, 30s의 대기시간으로 테스트 설정한 대기시간 만큼 대기하고 Timeout발생 기대 isElementPresentTest() 설정값 10s의 대기시간 테스트 10s 후 timeout발생 기대 implicitlyWaitTest() fi ndElement 함수를 사용할 경우 default timeout 5초 적용 테스트 5s 후 timeout발생 기대 implicitlyWait + waitForVisibilityTestWithTimeout() implicitlyWait = 5s 7, 15, 20, 30s의 대기시간으로 테스트 진행 설정한 대기시간 만큼 대기하고 Timeout발생 기대
  49. - Implicit wait & Explicit wait - 배경: • 화면

    전환 시 로딩이 느린 이슈 • Explicit Wait의 timeout 시간이 기대보다 더 걸리는 이슈 - 결과: • Implicit Wait만 사용한 경우, 5초로 기대한 시간과 동일 • Timeout 시간이 설정한 시간보다 1~5초 더 발생 • Explicit Wait의 timeout값은 Implicit Wait보다 커야함 Performance Improvement Studies Implicit Wait = 최소화 Explicit Wait = 상황별 최적화
  50. Performance Improvement Studies 방안 설명 Limit The Search Scope 동일한

    루트 요소에서 여러 검색이 실행될 경우, 특정 요소로 제한 후 검색 시 검색 성능을 적절하게 최적화 가능 fi ndElements 대신 fi ndElement 사용 fi ndElements가 fi ndElement보다 모든 요소를 검색하는 데 더 많은 시간 소요 Avoid Generic Matchers asterisk(*)와 같은 Generic Matcher는 각 UI 요소의 모든 속성을 스캔하므로 추천하지 않음 - iOS 성능개선 방안4)에 따른 적용 테스트 진행 4) Meta Archive Github, “appium wda improve speed”, 2020년11월 20일, https:/ /github.com/facebookarchive/WebDriverAgent/wiki/How - To - Achieve - The - Best - Lookup - Performance
  51. Performance Improvement Studies 방안 설명 Limit The Search Scope 동일한

    루트 요소에서 여러 검색이 실행될 경우, 특정 요소로 제한 후 검색 시 검색 성능을 적절하게 최적화 가능 fi ndElements 대신 fi ndElement 사용 fi ndElements가 fi ndElement보다 모든 요소를 검색하는 데 더 많은 시간 소요 Avoid Generic Matchers asterisk(*)와 같은 Generic Matcher는 각 UI 요소의 모든 속성을 스캔하므로 추천하지 않음 - iOS 성능개선 방안4)에 따른 적용 테스트 진행 4) Meta Archive Github, “appium wda improve speed”, 2020년11월 20일, https:/ /github.com/facebookarchive/WebDriverAgent/wiki/How - To - Achieve - The - Best - Lookup - Performance 전체 소스를 스캔하는 방식은 지양
  52. 서비스 커버리지 투자 보험 전자문서 인증 영수증 자산관리 대출 …

    결제 해외결제 송금결제 온라인결제 쿠폰결제 포인트결제 … 충전 머니 뿌리기 친구송금 쿠폰교환 QR송금 예약충전 정산하기 예약송금 계좌송금 … 오프라인결제
  53. 테스트케이스 커버리지 * 사용자 지표가 높은 컴포넌트 및 우선순위 등

    내부 기준에 따라 선정된 테스트케이스에 대한 구현 비율 80% 테스트케이스 커버리지 유지