UITest

김재형_LittleTale·2025년 10월 27일

Testable

목록 보기
2/2

들어가기에 앞서

이전편 Unit Test를 보신후 참고하시면 좋습니다.

UITest

말 그래도 UI가 정상 동작하는가 즉
예측한 대로 동작하는가에 관한 자동화 테스트를 말함

Syntax

.accessibilityIdentifier(<#T##identifier: String##String#>)
   --- or ---
   accessibilityIdentifier = "Identifier"

위 같은 식별자를 통해 UI가 정상 동작하는지 테스트 하는 원리

XCTAssert


let app = XCUIApplication()

// okay button이 있는 경우 성공
XCTAssert(app.buttons["okay"].exists)

// "Hello World" 라는 문자열이 있는 경우 성공
XCTAssert(app.staticTexts["Hello World"].exists)

// 2초 내로 "TEST2" 라는 문자열이 보여지는 경우 성공
XCTAssert(app.staticTexts["TEST2"].waitForExistence(timeout: 2))

// image1 이라는 이미지가 있는 경우 성공
XCTAssert(app.images["image1"].exists, "There is no image1 image")

// 실패
XCTFail()

Action

let app = XCUIApplication()
app.buttons["button"].tap()
app.buttons["doubleTapButton"].doubleTap()

식별자를 통해 버튼을 찾고 액션을 준다.

let pointX = app.frame.width/2
let pointY = app.frame.height/2

let pointLocation = CGVector(dx: pointX, dy: pointY)
let normalizedLocation = app.coordinate(withNormalizedOffset: CGVector(dx:0, dy: 0))

let tapLocation = normalizedLocation.withOffset(pointLocation)
tapLocation.tap()

좌표를 통해 특정 지점을 탭 해도록 한다.

예시

import XCTest
@testable import Testable

@MainActor
final class TestableUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false
        
        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }
    
    func testTappedStartButton() {
        let app = XCUIApplication()
        let id = TestIdentifiers.contentViewStartButton.identifier
        let startButton = app.buttons[id]
        
        guard startButton.exists else {
            XCTFail("Lost Start Button")
            return
        }
        
        startButton.tap()
    }

    func testStartButtonExistsAndTap() {
        let app = XCUIApplication()
        app.launch()
        let startButton = app.buttons[TestIdentifiers.contentViewStartButton.identifier]
        XCTAssertTrue(startButton.waitForExistence(timeout: 3), "Start button should exist")
        startButton.tap()
    }

    func testSumTextExists() {
        let app = XCUIApplication()
        app.launch()
        let sumText = app.staticTexts[TestIdentifiers.contentViewSumText.identifier]
        XCTAssertTrue(sumText.waitForExistence(timeout: 3), "Sum label should exist")
    }

    func testStartThenSumChanges() {
        let app = XCUIApplication()
        app.launch()
        let startButton = app.buttons[TestIdentifiers.contentViewStartButton.identifier]
        let sumText = app.staticTexts[TestIdentifiers.contentViewSumText.identifier]
        
        XCTAssertTrue(startButton.waitForExistence(timeout: 3), "Start button should exist")
        XCTAssertTrue(sumText.waitForExistence(timeout: 3), "Sum label should exist")
        
        let initialValue = sumText.label
        startButton.tap()
        
        let predicate = NSPredicate { _, _ in sumText.exists && sumText.label != initialValue }
        let exp = expectation(for: predicate, evaluatedWith: nil, handler: nil)
        wait(for: [exp], timeout: 5.0)
        
        XCTAssertNotEqual(sumText.label, initialValue, "Sum label should change after loading numbers")
    }
}

추가설명

let p = NSPredicate { _, _ in sumText.exists && sumText.label != initialValue }

참 거짓 구분위한 객체 구성

expectation -> XCTestExpection

비동기 조건이 충족될 때가지 가디리는 방식
일정 시간 동안 재시도

let exp = expectation(for: predicate, evaluatedWith: nil, handler: nil)

Expection 정의

wait(for: [exp], timeout: 5.0)

5초까지 비동기(expectation) 종료를 대기

마무리 하며

이번엔 UITest를 다루어 보았습니다.
사실 이것 외에도 더 많은 메서드나 방식이 존재하는데
그런 부분은 찾아보면서 하는게 더 맞는 방법인 것 같아
여기까지 정리 해보도록 하겠습니다.
아직 Testable 에 대해서 다루지 않아서 다시 다루긴 할 겁니다.

예고

다음 시간은 아마 Transition Animation 에 대해서 다루어 보도록 하겠습니다.
WWDC 2024 글을 참고할 예정이니 많은 관심 부탁 드립니다.

profile
IOS 개발자 새싹이, 작은 이야기로부터

0개의 댓글