엔지니어링 노트

클라우드 Mac에서 iOS 접근성 회귀 게이트 구축하기

클라우드 Mac에서 iOS 접근성 회귀 게이트 구축하기

일반적인 버튼 이름 변경, 아이콘 교체, 제약 조건 조정만으로도 iOS 화면에서 읽을 수 있는 레이블이 사라지거나 탭 영역이 좁아지고, 큰 글자 크기에서 텍스트가 잘릴 수 있습니다. 모든 커밋을 사람이 직접 점검하기는 어렵습니다. 더 안정적인 방법은 클라우드 Mac에서 시뮬레이터와 앱 상태를 고정하고 XCTest로 접근성 감사를 실행한 뒤, 실패를 재현 가능한 병합 게이트로 만드는 것입니다.

먼저 게이트 범위 정의하기

처음부터 제품 전체를 순회하지 마세요. 로그인 후 홈 화면, 핵심 편집 화면, 제출 확인 화면처럼 자주 사용하는 경로를 먼저 선택하고, 각 테스트 케이스에서는 안정적인 상태 하나만 검증합니다. 애니메이션, 무작위 추천, 현재 시각, 네트워크 응답값은 요소 트리를 바꿀 수 있으므로 테스트 모드에서 비활성화하거나 고정 데이터를 주입해야 합니다.

첫 단계에서는 다음 네 가지 유형의 문제를 검사하는 것이 좋습니다.

검사 항목 흔한 결함 게이트 처리
요소 설명 아이콘 버튼에 읽을 수 있는 이름이 없음 즉시 실패
탭 영역 컨트롤은 보이지만 누르기 어려움 즉시 실패
대비 전경과 배경을 구분하기 어려움 디자인 확인 후 수정
텍스트 레이아웃 큰 글자 크기에서 잘리거나 겹침 즉시 실패

자동 감사는 시스템이 안정적으로 판단할 수 있는 문제를 찾는 역할을 하며, 전체 상호작용이 사용하기 쉽다는 사실까지 입증하지는 않습니다. 읽기 순서, 안내의 명확성, 복잡한 제스처는 계속 사람이 직접 확인해야 합니다.

테스트 화면을 결정적인 상태로 만들기

UI 테스트에서 가장 피해야 할 상황은 “같은 진입점인데 다른 화면이 표시되는 것”입니다. 앱은 테스트 전용 시작 인수를 인식하고, 시작할 때 임시 상태를 지우고 고정 데이터를 불러오며 불필요한 애니메이션을 비활성화해야 합니다. 이 인수는 테스트 환경만 변경해야 하며 실제 비즈니스 로직에 포함되어서는 안 됩니다.

let app = XCUIApplication()
app.launchArguments = [
    "-ui-testing",
    "-reset-demo-state",
    "-disable-animations"
]
app.launchEnvironment["TEST_LOCALE"] = "zh-Hans"
app.launch()

테스트 데이터는 앱 프로세스 내부에서 준비하고, UI 테스트가 실시간 API에 의존하지 않도록 해야 합니다. 로딩, 빈 데이터, 오류, 정상 결과를 모두 다뤄야 한다면 상태별로 독립된 인수를 만드세요. 그러면 실패 후 명령만 복사해 재현할 수 있으며, 특정 원격 조건이 다시 발생할 때까지 기다릴 필요가 없습니다.

요소 식별 방식 고정하기

중요한 컨트롤을 버튼 제목이나 좌표로 찾지 마세요. 제목은 현지화에 따라 바뀌고 좌표는 창과 글자 크기에 따라 달라집니다. 상호작용 가능한 요소에는 의미가 안정적인 accessibilityIdentifier를 설정합니다.

checkoutButton.accessibilityIdentifier = "checkout.submit"
cartSummary.accessibilityIdentifier = "checkout.summary"

식별자는 시각적 위치가 아니라 역할을 설명해야 합니다. footer.orangeButton 같은 이름은 디자인이 바뀌면 의미를 잃지만, checkout.submit은 레이아웃이 달라져도 계속 사용할 수 있습니다.

범위를 지정해 XCTest 감사 실행하기

시스템 버전이 관련 API를 지원한다면 안정적인 상태에 도달한 화면을 대상으로 감사를 실행할 수 있습니다. 먼저 핵심 요소가 나타날 때까지 기다린 다음 검사를 시작해야 로딩 중의 임시 레이아웃을 결함으로 잘못 판단하지 않습니다.

func testCheckoutAccessibility() throws {
    let app = XCUIApplication()
    app.launchArguments = ["-ui-testing", "-reset-demo-state"]
    app.launch()

    let submit = app.buttons["checkout.submit"]
    XCTAssertTrue(submit.waitForExistence(timeout: 10))

    if #available(iOS 17.0, *) {
        try app.performAccessibilityAudit(for: [
            .sufficientElementDescription,
            .hitRegion,
            .contrast,
            .textClipped
        ])
    }
}

전역 무시 목록을 무심코 만들지 마세요. 일시적으로 제외해야 한다면 명확한 화면, 요소 식별자, 문제 유형으로 범위를 제한하고 코드 리뷰에 제거 조건을 명시해야 합니다. 그렇지 않으면 무시 항목이 점차 영구적인 사각지대로 굳어집니다.

클라우드 Mac 실행 조건 고정하기

먼저 현재 사용할 수 있는 시뮬레이터 기기와 런타임을 확인한 뒤, 파이프라인에서 확정된 destination을 전달합니다. 모든 노드에 같은 이름의 기기가 이미 존재한다고 가정해서는 안 됩니다.

xcrun simctl list devices available
xcrun simctl list runtimes

export SIM_DESTINATION='platform=iOS Simulator,name=iPhone 15,OS=17.5'

set -o pipefail
xcodebuild test \
  -project ExampleApp.xcodeproj \
  -scheme ExampleAppUITests \
  -destination "$SIM_DESTINATION" \
  -only-testing:ExampleAppUITests/AccessibilityTests \
  -resultBundlePath "$PWD/TestResults/Accessibility.xcresult"

실제로 실행할 때는 기기 이름과 시스템 버전을 파이프라인 변수로 관리하고, 노드에 설치된 런타임과 일치시켜야 합니다. 실행 전에 새 시뮬레이터를 생성하거나, 기기를 재사용한다면 먼저 앱을 종료하고 테스트 상태를 정리합니다. 병렬 작업에서 같은 시뮬레이터를 공유하지 마세요. 언어 설정, 권한 팝업, 이전 테스트 케이스의 잔여 상태가 서로 영향을 줄 수 있습니다.

클라우드 Mac의 모델이나 노드 선택은 테스트 설계 원칙을 바꾸지 않습니다. 실행 환경을 추가해야 한다면 콘솔에서 현재 선택 가능한 구성을 확인하고 Xcode 버전, 런타임 버전, 언어, destination을 기록해야 합니다. 그래야 실패를 동일한 조건에서 다시 실행할 수 있습니다.

계층별로 실행하고 흔한 오탐 처리하기

각 병합 요청에서는 핵심 화면, 기본 언어, 표준 글자 크기만 실행해 피드백 시간을 팀이 허용할 수 있는 범위로 유지합니다. 메인 브랜치에서는 다국어, 가로·세로 화면, 다크 모드, 동적 글자 크기까지 범위를 확장합니다. 모든 조합을 하나의 테스트 메서드에 넣지 마세요. 화면과 상태별로 분리하면 실패한 테스트 이름만으로도 범위를 파악할 수 있습니다.

불안정한 실패가 발생하면 다음 순서로 확인합니다.

  1. 핵심 요소가 요소 트리에 존재하기만 하는 것이 아니라 로딩까지 완료했는지 확인합니다.
  2. 언어, 지역, 글자 크기, 화면 방향, 화면 모드 설정을 비교합니다.
  3. 이전 실행에서 테스트 데이터가 변경되지 않았는지 확인합니다.
  4. 실패한 메서드만 다시 실행해 문제가 안정적으로 재현되는지 확인합니다.
  5. 테스트 결과 번들, 실행 명령, 환경 필드를 저장한 뒤 제품 결함인지 테스트 격리 부족인지 판단합니다.

게이트 규칙도 단계별로 나눠야 합니다. 설명 누락, 탭 불가, 텍스트 겹침은 병합을 차단하기에 적합합니다. 디자인 확인이 끝나지 않은 대비 문제는 우선 기록할 수 있지만, 반드시 담당자와 처리 기한을 지정해야 합니다. 최종 목표는 언제나 모두 통과하는 보고서를 얻는 것이 아니라, 실패할 때마다 화면, 상태, 요소, 환경 조건까지 정확히 찾아낼 수 있게 하는 것입니다.

자주 묻는 질문

자동 접근성 감사가 수동 검사를 완전히 대체할 수 있나요?

대체할 수 없습니다. 누락된 설명, 작은 터치 영역, 낮은 명암비는 찾을 수 있지만 읽기 순서와 실제 조작 의미는 사람이 직접 확인해야 합니다.

로컬에서는 통과하지만 클라우드 Mac에서 실패하는 이유는 무엇인가요?

시뮬레이터 런타임, 언어, 지역, 글자 크기, 화면 방향과 테스트 데이터를 비교해야 합니다. 모든 조건을 시작 인수로 고정하면 차이를 줄일 수 있습니다.

전체 접근성 감사는 언제 실행하는 것이 좋나요?

핵심 화면의 빠른 검사는 변경 요청마다 실행하고, 다국어와 여러 글자 크기를 포함한 전체 행렬은 기본 브랜치나 예약 작업에서 실행하는 방식이 적합합니다.

독점 물리 노드

다음 빌드를 클라우드 Mac에서 실행하세요.

세 가지 Apple Silicon 구성을 비교하고, 현재 워크플로에 맞는 리전을 5개의 해외 노드 중에서 선택하세요.

대여 플랜 선택