편집 화면에서는 세로 모드로 입력할 때 문제가 없지만, 가로 모드로 전환하면 작성 중인 초안이 사라질 수 있습니다. 저장 버튼이 뷰 계층에는 남아 있어도 키보드에 가려 눌리지 않는 경우도 있습니다. 이런 문제는 클라우드 Mac에서 빌드만 한 번 실행해서는 발견할 수 없습니다. UI 테스트가 실제로 ‘입력—회전—저장—세로 모드로 복귀’ 과정을 거쳐야 합니다. 아래에서는 초안 편집 화면이 있는 iOS 앱을 예로 들어 반복 실행할 수 있는 점검 절차를 만듭니다.
회전 후에도 유지해야 할 상태 정의하기
테스트 전에 편집 필드, 저장 버튼, 저장 결과에 각각 안정적인 accessibilityIdentifier인 draftEditor, saveDraft, savedStatus를 지정합니다. 이 식별자는 앱 코드에 속하며, 현지화된 버튼 문구로 요소를 찾는 방식에 의존해서는 안 됩니다. 테스트에서 확인할 조건은 다음과 같습니다. 화면을 회전해도 저장하지 않은 입력이 사라지지 않아야 하고, 가로 모드에서 저장 버튼을 누를 수 있어야 합니다. 저장 후에는 결과 안내가 나타나야 하며, 세로 모드로 돌아온 뒤에도 그 안내가 보여야 합니다.
exists는 요소가 접근성 트리에 남아 있다는 뜻일 뿐, 사용자가 실제로 누를 수 있다는 뜻은 아닙니다. 회전 테스트에서는isHittable도 확인하고 실제로 한 번 탭해야 합니다.
먼저 앱이 테스트할 화면 방향을 지원하는지 확인합니다. 프로젝트의 기기 방향 설정에서 가로 모드를 비활성화했다면, 회전할 수 없는 상태를 레이아웃 오류로 잘못 판단해서는 안 됩니다. 태블릿과 휴대폰에도 검증하지 않은 동일한 기대값을 적용하지 마세요. 분할 화면 레이아웃, 키보드 크기, 안전 영역이 다를 수 있습니다.
시뮬레이터와 실행 환경 고정하기
XcodeOps 클라우드 Mac의 그래픽 세션에서 먼저 xcrun simctl list devices available을 실행합니다. 설치된 런타임에 속한 휴대폰 시뮬레이터 한 대를 선택하고 UDID를 기록합니다. CI에서는 기기 이름만으로 대상을 찾지 마세요. 같은 이름의 기기가 서로 다른 런타임에 속할 수 있습니다. UDID를 SIMULATOR_UDID 환경 변수로 작업에 전달하고, 시작 전에 해당 기기가 여전히 사용 가능한 기기 목록에 있는지 다시 확인합니다.
하나의 기준 테스트에서는 Xcode 선택 경로, 시뮬레이터 UDID, 앱 테스트 데이터, 테스트 진입점을 고정해야 합니다. xcodebuild -version과 xcrun simctl list devices available의 출력은 작업 기록과 함께 보관하면 됩니다. 다른 시뮬레이터의 결과를 이 기준 결과에 섞지 마세요. UI 테스트에는 사용 가능한 그래픽 로그인 세션도 필요합니다. SSH로 접속할 수 있다고 해서 테스트 프로세스가 반드시 시뮬레이터 창을 조작할 수 있는 것은 아닙니다.
전체 왕복 과정을 검증하는 UI 테스트 작성하기
아래 테스트를 프로젝트의 UI Test target에 추가합니다. 이 예시는 앱을 실행하면 편집 화면이 바로 나타나고, 앱에 앞서 설명한 세 식별자가 이미 지정되어 있다고 가정합니다. 편집 화면까지 이동해야 한다면 이전 실행에서 남은 화면 상태에 의존하지 말고, 입력 전에 탐색 단계를 명시적으로 수행해야 합니다.
import XCTest
final class RotationTests: XCTestCase {
func testDraftSurvivesRotation() {
let device = XCUIDevice.shared
device.orientation = .portrait
defer { device.orientation = .portrait }
let app = XCUIApplication()
app.launch()
let editor = app.textViews["draftEditor"]
XCTAssertTrue(editor.waitForExistence(timeout: 10))
editor.tap()
editor.typeText("Rotation check 42")
device.orientation = .landscapeLeft
XCTAssertTrue(
NSPredicate(format: "value == %@", "Rotation check 42")
.evaluate(with: editor)
)
let save = app.buttons["saveDraft"]
XCTAssertTrue(save.waitForExistence(timeout: 10))
XCTAssertTrue(save.isHittable)
save.tap()
let status = app.staticTexts["savedStatus"]
XCTAssertTrue(status.waitForExistence(timeout: 10))
device.orientation = .portrait
XCTAssertTrue(status.waitForExistence(timeout: 10))
}
}
여기서 defer는 다음 테스트가 시작되기 전에 화면을 가급적 세로 모드로 되돌리기 위한 장치입니다. 각 테스트가 자체적으로 초기 상태를 설정하는 일을 대신하지는 못합니다. 앱이 회전할 때 편집 뷰를 다시 만들더라도 기존 요소 쿼리는 대체로 다시 해석할 수 있습니다. 하지만 쿼리에서 얻은 좌표나 frame을 캐시해서는 안 됩니다. 비동기 저장에서는 안내가 나타나기를 기다리는 것만으로 충분하지 않습니다. 앱이 명확한 성공 상태를 제공하도록 하고 그 값을 단언해야 ‘저장 중’을 완료로 잘못 판단하지 않습니다.
명령줄에서 실행하고 결과 보관하기
프로젝트 디렉터리에서 테스트를 실행할 때는 먼저 프로젝트 경로, 공유 Scheme, 앞서 기록한 UDID를 설정합니다. 아래 명령은 필수 변수가 비어 있으면 즉시 종료하고 테스트 결과를 새 결과 번들 디렉터리에 기록합니다. 다시 실행하기 전에는 디렉터리 이름을 바꿔야 합니다.
: "${PROJECT:?Set the Xcode project path}"
: "${SCHEME:?Set a shared test scheme}"
: "${SIMULATOR_UDID:?Set an available simulator UDID}"
xcodebuild test \
-project "$PROJECT" \
-scheme "$SCHEME" \
-destination "platform=iOS Simulator,id=$SIMULATOR_UDID" \
-only-testing:AppUITests/RotationTests/testDraftSurvivesRotation \
-resultBundlePath "$PWD/rotation-run.xcresult"
AppUITests는 프로젝트의 UI Test target 이름과 일치해야 합니다. 테스트가 실패하면 .xcresult를 보관하고 실패 단계, 스크린샷, 테스트 로그를 함께 살펴 입력이 초기화된 것인지 버튼이 가려진 것인지 판단합니다. 터미널의 마지막 줄만 보지 마세요. 스크립트로 결과를 읽어야 한다면 먼저 xcrun xcresulttool help로 현재 Xcode에서 제공하는 하위 명령을 확인한 뒤 적절한 구조화 출력 방식을 선택합니다.
무작정 대기 시간을 늘리지 말고 증상별로 조사하기
| 증상 | 먼저 확인할 사항 | 수정 방향 |
|---|---|---|
| 가로 모드로 전환한 뒤 초안이 사라짐 | 회전할 때 뷰가 다시 만들어지는지, 상태를 어디에서 보유하는지 | 뷰가 다시 만들어져도 유지되는 위치에 편집 상태 보관 |
| 버튼은 있지만 누를 수 없음 | 키보드, 오버레이, 안전 영역, 스크롤 컨테이너 | 제약 조건을 수정하거나 키보드를 닫는 명확한 경로 제공 |
| CI에서만 실패함 | 그래픽 세션, 시뮬레이터 런타임, 테스트 데이터 | 실행 대상을 고정하고 작업 시작 상태를 일치시킴 |
| 세로 모드로 돌아온 뒤 안내가 사라짐 | 안내가 잠깐 나타나는 애니메이션에 불과한지 | 지속되는 저장 결과를 확인하거나 데이터를 다시 읽음 |
가로 모드에서 실패했다고 곧바로 고정된 sleep을 추가하지 마세요. 화면에 실제 전환 과정이 있다면 특정 요소가 검증 가능한 상태에 도달하기를 기다립니다. 버튼이 계속 키보드에 가려져 있다면 더 오래 기다려도 누를 수 있게 되지 않습니다. 특정 화면 크기에서만 문제가 나타난다면 화면 크기가 다른 시뮬레이터를 두 번째 대상으로 추가하되, 모든 기기를 단일 테스트에 한꺼번에 넣지는 마세요. 먼저 실행 대상을 고정한 왕복 경로 하나를 안정화한 뒤 범위를 넓혀야 실패 기록을 의미 있게 비교할 수 있습니다.
자주 묻는 질문
시뮬레이터만으로 화면 회전을 검증할 수 있나요?
화면 상태와 컨트롤의 터치 가능 여부는 확인할 수 있습니다. 센서 동작과 실제 사용성은 기기에서도 점검하세요.
버튼이 보이는데도 탭 테스트가 실패하는 이유는 무엇인가요?
키보드나 다른 화면이 버튼을 가렸는지 먼저 확인하고, 안전 영역 제약과 회전 중 화면 재생성을 살펴보세요.
다음 작업에 맞춰 클라우드 Mac 구성하기
모델의 메모리 용량이나 빌드 작업량에 맞춰 Mac mini를 선택하세요. 세 가지 모델을 일·주·월·분기 단위로 대여할 수 있으며, 노드의 실시간 이용 가능 여부는 콘솔에서 확인할 수 있습니다.