UITest) UITest 시작하기

SteadySlower·2023년 6월 1일
0

iOS Development

목록 보기
17/38

이 포스팅은 사내에서 진행한 Tech Talk을 정리한 포스팅입니다.

본격적으로 UITest를 작성하는 법을 소개해보도록 하겠습니다.

테스트할 앱 소개

Tech Talk에 예시로 사용한 앱을 소개하겠습니다. 앞으로 이 앱으로 UITest를 작성하는 법을 소개하겠습니다.

간단한 영어 퀴즈앱인데요. 처음에 앱을 실행하면 자신의 이름을 입력하는 화면이 뜹니다.

이름은 5글자 이상으로 입력해야 합니다. 5글자 이하의 이름을 입력하게 되면 alert로 5글자 이상의 이름을 입력하라는 메시지가 출력됩니다.

이름을 입력하면 앱 상단에 “Let’s Quiz, (username)!”이 출력됩니다. 그림 힌트를 탭하면 그림힌트 화면으로 넘어갑니다.

정답을 입력하면 정답입니다라는 alert와 함께 버튼의 이름이 다음 문제로 바뀌고 누르면 다음 문제를 풀 수 있습니다.

문제를 틀리면 틀렸습니다라는 alert가 뜨는 간단한 퀴즈 앱입니다.

세팅 함수 설정

테스트에 사용하는 클래스는 UnitTest와 동일한 XCTestCase입니다. 테스트 이전에 실행할 코드를 작성하기 위해서 사용하는 함수도 동일하게 setUpWithError입니다.

차이점은 테스트의 대상이 XCUIApplication, 즉 앱 자체라는 점입니다. 테스트 이전에 app을 launch 해야지만 UI 테스트를 할 수 있습니다.

class UITests_Name: XCTestCase {
    
    let app = XCUIApplication()

    override func setUpWithError() throws {
        continueAfterFailure = false
        app.launch()
    }

}

UITest Record 하기


저번 포스팅에 다루었다 시피 UITest에 필요한 코드는 UnitTest에 필요한 코드 보다 복잡합니다. 이 코드를 전부 직접 작성해야 한다면 상당히 복잡하겠죠? Xcode에서는 이런 수고를 덜어주기 위해서 UI를 직접 조작하면 해당 조작을 코드로 바꾸어주는 기능을 제공합니다.

해당 기능을 사용해서 TextField에 이름을 작성하는 코드를 만들어 보겠습니다. 제가 한 동작은 아래와 같습니다.

  1. 녹화 버튼을 누르기
  2. 텍스트 필드를 탭한 다음,
  3. 한글 키보드를 영어 키보드로 바꾸기
  4. 키보드의 “T”, “e”, “d”, “d”, “y”를 순서대로 누르기
  5. 입력 버튼을 탭하기
  6. 퀴즈화면으로 전환된 이후에 이름이 포함된 텍스트 탭하기
  7. 녹화 종료 버튼 누르기

위 동작을 실시하면 아래와 같은 코드가 자동으로 생성됩니다.

let app = XCUIApplication()
app.textFields["이름"].tap()
app.buttons["Next keyboard"].tap()

let tKey = app.keys["T"]
tKey.tap()
tKey.tap()

let eKey = app.keys["e"]
eKey.tap()
eKey.tap()

let dKey = app.keys["d"]
dKey.tap()
dKey.tap()
dKey.tap()

let yKey = app.keys["y"]
yKey.tap()
yKey.tap()
app.buttons["입력"].tap()
app.staticTexts["Let's Quiz, Teddy!"].tap()

굉장히 편리한 기능이지만 이 그대로 테스트로 사용할 수는 없습니다. 일단 왜 인지는 모르겠지만 키보드를 입력할 때 tap()이 두번 씩 입력된 것을 볼 수 있습니다. 불필요한 tap은 삭제해줍니다.

그리고 우리는 앱 객체를 XCTestCase 클래스 내부에 선언해두고 세팅 함수를 통해 launching까지 해둔 상태입니다. 새로운 앱 객체를 만들지 않고 해당 객체를 활용해도록 하겠습니다.

마지막으로 마지막에 tap해서 얻은 객체인 staticTexts는 앱이 제대로 작동했는지 확인하기 위함입니다. 해당 객체는 tap 하는 동작을 XCTAssert를 통해서 존재하는지 하지 않는지 확인하는 코드로 변경해보도록 하겠습니다.

그리고 해당 코드를 하나로 묶는 함수명을 지어보도록 하겠습니다. XCTestCase에서 테스트 함수로 인식되기 위해서는 “test”로 시작해야 합니다.

완성된 코드는 아래와 같습니다.

func test_NameView_inputButton_success() {

    app.textFields["이름"].tap()
    app.buttons["Next keyboard"].tap()

    let tKey = app.keys["T"]
    tKey.tap()

    let eKey = app.keys["e"]
    eKey.tap()

    let dKey = app.keys["d"]
    dKey.tap()
    dKey.tap()

    let yKey = app.keys["y"]
    yKey.tap()

    app.buttons["입력"].tap()
    XCTAssert(app.staticTexts["Let's Quiz, Teddy!"].exists)
    
}

해당 함수를 만들면 좌측에 테스트 실행 버튼이 생깁니다. 해당 버튼을 눌러서 테스트를 실시하면 시뮬레이터에서 앱이 자동으로 실행되고 코드에 정의된 동작으로 자동으로 실시합니다. 해당 동작이 끝난 이후에는 테스트의 결과를 받아볼 수 있습니다.

Tip) 키보드를 조작하는 함수 리팩토링

앞으로 앱을 테스트하면서 키보드를 조작할 일이 많습니다. 그 때마다 일일히 위처럼 모든 동작을 풀어서 쓸 수는 없습니다. 해당 동작을 함수로 만들어 두고 사용해봅시다.

주의할 점은 시뮬레이터의 언어가 한국어로 설정이 되어 있다면 기본적으로 키보드는 한글과 영어 2종류입니다. 위 코드를 실행해보신 분들은 아시겠지만 한글 키보드에서 app.keys["T"] 코드가 실행되면 테스트가 실패하게 됩니다. UI에 해당 키가 없기 때문입니다.

따라서 만약에 키보드가 영어가 아니라면 buttons["Next keyboard"]를 탭해서 영어 키보드로 바꾸는 동작을 추가합니다. (키보드 좌하단은 지구본 모양 버튼을 의미합니다.)

String을 받아서 키보드에 입력하는 완성된 함수는 아래와 같습니다.

// 키보드로 이름 입력
func inputName(_ name: String) {
    // textField 찾아서 탭
    let textField = app.textFields["이름"]
    textField.tap()
    
    // 키보드가 영문인지 확인하고 아니면 next keyboard 버튼
    let isKeyboardEngish = app.keyboards.keys["A"].exists
    if !isKeyboardEngish {
        app.buttons["Next keyboard"].tap()
    }
    
    // String을 char로 풀어서 하나하나 입력
    for char in name {
        let key = app.keyboards.keys["\(char)"]
        key.tap()
    }
    
    // 입력 버튼 탭
    let inputButton = app.buttons["입력"]
    inputButton.tap()
}
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글