데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      에이닷 UI 테스트 자동화이야기: XCTest를 이용한 iOS 앱 테스트

      bobby.kim 24.06.27
      3,885 12 0
      DEVOTEE 요약
      이 글에서는 iOS 앱 테스트 자동화를 위해 Apple의 XCTest를 사용하는 방법을 다룹니다. 주로 UI 테스트에 초점을 맞추며 접근성 설정, 기본적인 테스트 기법, 딜레이 해결, 디버깅 방법, 그리고 xctestplan을 활용한 테스트 커스터마이징을 설명합니다. XCTest를 통해 앱의 안정성과 품질을 향상시킬 수 있으므로, 이를 프로젝트에 도입해보시길 권장드립니다.

      안녕하세요. 에이닷에서 UITest 적용을 검토하기 위해 선행 조사한 내용을 공유드리고자 합니다.

      이번 포스트에서는 iOS에서 제공하는 XCTest를 활용한 자동화 테스트 솔루션에 대해 다루겠습니다.

      XCTest 활용하기

      XCTest는 Apple에서 제공하는 테스트 프레임워크로, iOS 및 macOS 앱의 테스트를 자동화하는 데 널리 사용됩니다.

      XCTest를 통해 단위 테스트, UI 테스트, 성능 테스트 등을 수행할 수 있습니다.

      이번 글에서는 다양한 방법 중 UI 테스트에 초점을 맞추어 진행 중인 서비스에 도입하려는 준비 과정을 설명하겠습니다.

      UI 테스트는 사용자 관점에서의 테스트이기 때문에, 앱과 서버 간의 전체적인 테스트를 수행할 수 있어 서비스에 적용하면 많은 효율성을 기대할 수 있습니다.

      접근성(Voice Over)

      iOS에서 XCTest를 작성하기 전에 알아두어야 할 것은 접근성(Voice Over)입니다.

      XCTest에서 요소를 검색하고, 클릭 및 스크롤할 때 핵심이 되는 것은 Accessibility Identifier입니다.

      직접 화면에 보이는 텍스트를 이용해 접근할 수도 있지만, 테스트 케이스 작성 후 추후 앱의 시나리오가 변경될 때 유지보수를 고려한다면 고유한 ID값이 필수적입니다.

      따라서 진행 중인 프로젝트의 화면 요소들에 Accessibility Identifier를 설정하는 것부터 준비해야 합니다.

      Accessibility Identifier는 실제 사용자에게는 영향을 주지 않으므로 기존 서비스에 영향을 미치지 않습니다.


      SwiftUI에서 Accessibility Identifier 세팅하기:

      Text("Hello, world!")
          .accessibilityIdentifier("id:label_main_text")

      예제로 보는 테스트 가능 범위

      Accessibility Identifier 설정이 완료되었다면, XCTest를 이용해 테스트 케이스를 작성해볼 차례입니다.

      SwiftUI를 기반으로 설명드리겠습니다.


      기본적으로 준비해볼 부분은 아래와 같습니다.

      • 텍스트 검색

      • 버튼 클릭

      • 리스트 아이템의 순서 확인 및 하위 뷰 데이터 확인


      텍스트 검색

      다음과 같은 방법으로 element를 찾을 수 있습니다.

      let labelID = "id:label_main_text"
      let labelText = "Hello, world!"
      let label = XCUIApplication().staticTexts[labelID]
      
      XCTAssertTrue(label.exists, "\(labelID)이 존재해야 합니다.")
      XCTAssertEqual(label.label, labelText, "레이블 텍스트는 '\(labelText)'이어야 합니다.")

      버튼 클릭

      let button = app.buttons["id:button_move"]
      XCTAssertEqual(button.label, "테스트 버튼", "Button title should be '테스트 버튼'")
      button.tap()

      View의 하위 속성 조회하기

      • List와 같은 UI를 LazyVStack으로 구성했을 때, 아이템 순서별로 데이터를 조회할 수 있습니다.

      • element의 children 속성을 이용해 서버에서 받은 데이터로 구성된 화면의 하위 element를 확인할 수 있습니다.

      let list = app.otherElements["id:lazyvstack"]XCTAssertTrue(list.exists, "The list does not exist")
      let listElements = list.children(matching: .any).allElementsBoundByIndex
      for (index, item) in listElements.enumerated() {    
          let listItem = item.buttons["id:list_item_\(index)"]
          print("++ listItem element: \(listItem)")
          print("++ id:text_title: \(item.staticTexts["id:text_title"].label)") 
          print("++ id:text_discription: \(item.staticTexts["id:text_discription"].label)")
      }

      노하우 및 팁

      Delay가 필요한 element 체크

      • 실제 앱에서는 네트워크 연동과 같은 이유로 화면이 보여진후 2-3초정도 동안 특정 element 가 보여지는 지 체크 해야 할수 있습니다.

      • 다음과 같이 waitForExpectations를 사용해서 특정 시간까지 해당 elemen가 보여지는지 기다릴수 있습니다.

      • View의 Text를 체크 하거나, 클릭 액션을 취하는경우 앱의 구현에 따라서 Delay가 필요 할수 있기 때문에 아래와 같은 코드는 반복적으로 많이 사용되게 됩니다.

      extension XCTestCase {    
          /// 특정 텍스트가 나타날 때까지 기다리는 함수    
          /// - Parameters:    
          ///   - app: `XCUIApplication` 인스턴스    
          ///   - elementIdentifier: 접근성 식별자    
          ///   - timeout: 기다릴 최대 시간 (초 단위)    
          /// - Throws: 오류가 발생할 경우    
          func waitForElementToAppear(app: XCUIApplication, elementIdentifier: String, timeout: TimeInterval = 10) throws {
              let element = app.staticTexts[elementIdentifier] 
              let exists = NSPredicate(format: "exists == true")
              expectation(for: exists, evaluatedWith: element, handler: nil)
              waitForExpectations(timeout: timeout) { (error) in
                  if error != nil {
                      XCTFail("Element with identifier \(elementIdentifier) did not appear within \(timeout) seconds.")
                  }
              }
          }
      }

      디버깅

      TestCase를 작성하다보면, 생각처럼 동작을 하지 않을때가 있습니다.

      • Accessibility Identifier를 확인 하고 싶을때

      • 현재 화면의 구성을 확인해보고 싶을때

      • Log를 이용한 디버깅

        • 아래와 같은 Util 함수를 이용하여, 화면의 요소들을 Log로 확인할수 있도록 활용하였습니다.

      extension XCUIElement {    
          func printHierarchy(indentation: String = "") { 
              // 현재 요소 출력
              switch self.elementType {
                  case .staticText, .button:
                      print("++ \(indentation)Element: \(self.identifier), \(self.elementType.toString), \(self.label)")
                  default:
                      print("++ \(indentation)Element: \(self.identifier), \(self.elementType.toString)")        
              }
             
              let childrenQuery = self.children(matching: .any)
              if childrenQuery.count > 0 {
                  for index in 0..<childrenQuery.count {
                      let child = childrenQuery.element(boundBy: index)
                      child.printHierarchy(indentation: indentation + "  ")
                  }        
              }    
          }
      }
      • Accessibility Inspector 디버깅

        • Xcode에서 "Xcode -> Open Developer Tool -> Accessibility Inspector" 를 실행합니다.

        • 시뮬레이터나 디바이스에서 확인하고 element의 정보 및 Hierarchy 확인이 가능합니다.


      화면 캡쳐

      • 테스트케이스 실행중 에러가 발생했을 경우 해당문제를 리포트 하기 위해서 화면 캡쳐가 필요 할수 있습니다.

      • 아래와 같이 XCUIScreen, XCTAttachment를 활용해서 활용할수 있습니다.

      // 화면 캡처 찍기        
      let screenshot = XCUIScreen.main.screenshot()
      screenshot.image // 캡쳐된 이미지를 활용가능합니다.
      
      // 테스트 결과리포트에 해당 캡쳐 이미지의 이름을 지정해서 리포트에 추가할수 있습니다.
      let attachment = XCTAttachment(screenshot: screenshot)
      attachment.name = "Test Screenshot at \(Date())"
      attachment.lifetime = .keepAlways
      add(attachment)

      Test Plan을 활용한 Test 실행

      • Test를 실행할수 항상 전체 Testcase를 실행하는 것이 아닌 상황에 따라서 부분적으로 실행해야 할수 있습니다.

      • Xcode에서 지원하는 xctestplan을 사용하면 테스트 실행을 커스터마이징 할수 있습니다.

      • 사용방법

        • Xcode -> Edit Scheme -> "Test" 를 선택후 Test Plans에서 "+" 버튼 클릭하여 설정

        • 터미널에서 실행하기

          • 아래와 같이 test 옵션에 testPlan을 설정 하면 해당 testplane을 실행할수 있습니다.

      xcodebuild test -scheme YourScheme -destination 'platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro' -testPlan YourTestPlane

      맺음말

      이번 블로그 포스트에서는 iOS 앱 테스트 자동화를 위한 XCTest 활용 방법을 다루었습니다.

      XCTest는 강력한 테스트 프레임워크로, 특히 UI 테스트를 통해 사용자 관점에서 앱의 품질을 높이는 데 효과적입니다.

      접근성 설정의 중요성, 기본적인 UI 테스트 기법, 딜레이 해결 방법, 디버깅 기법, 그리고 xctestplan을 활용한 테스트 커스터마이징을 설명했습니다.

      XCTest를 통해 앱의 안정성과 품질을 향상시키는 것은 매우 중요합니다. 앞으로도 XCTest를 적극 활용하여 지속적으로 앱의 품질을 개선해 나갈 것입니다.

      여러분도 이번 포스트를 참고하여 자신의 프로젝트에 XCTest를 도입해 보시길 바랍니다.


      감사합니다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      bobby.kim 님의 최신 블로그

      더보기