클라우드 Mac CI에서 iOS UI 테스트 실패 영상 녹화하기

CI/CD ·약 8분 읽기

클라우드 Mac CI에서 iOS UI 테스트 실패 영상 녹화하기

클라우드 Mac에서 UI 테스트가 실패했을 때 단언 결과와 스크린샷만으로는 원인을 파악하기 어려운 경우가 많습니다. 팝업이 나타났다가 즉시 사라지거나, 화면 전환이 중간에서 멈추거나, 키보드가 버튼을 가리는 문제는 연속된 영상을 봐야 발생 순서를 알 수 있습니다. 모든 영상을 영구 보관하는 대신, 테스트 시작 전에 지정한 시뮬레이터의 화면을 녹화하고 테스트가 성공하면 삭제하며, 실패한 경우에만 영상, 로그, 결과 번들을 함께 보관하는 방식이 가장 안정적입니다.

테스트 기기와 증거 수집 범위 고정하기

녹화 명령에 booted를 직접 넘기지 마세요. 병렬 작업, 이전 작업의 비정상 종료로 남은 기기 또는 수동 디버깅으로 인해 여러 시뮬레이터가 동시에 부팅되어 있을 수 있으며, 이 경우 잘못된 기기의 화면이 녹화될 수 있습니다. 먼저 현재 작업 전용 기기를 생성하거나 찾아 UDID를 얻은 다음, 부팅, 테스트, 녹화, 정리 단계에 동일한 UDID를 전달해야 합니다.

DEVICE_NAME="CI-iPhone"
RUNTIME="com.apple.CoreSimulator.SimRuntime.iOS-18-0"
DEVICE_TYPE="com.apple.CoreSimulator.SimDeviceType.iPhone-16"

UDID="$(xcrun simctl list devices available -j |
  plutil -extract devices json -o - - |
  jq -r --arg name "$DEVICE_NAME" '
    .. | objects | select(.name? == $name) | .udid
  ' | head -n 1)"

if [ -z "$UDID" ]; then
  UDID="$(xcrun simctl create "$DEVICE_NAME" "$DEVICE_TYPE" "$RUNTIME")"
fi

xcrun simctl boot "$UDID" 2>/dev/null || true
xcrun simctl bootstatus "$UDID" -b

런타임 식별자는 설치된 Xcode에 따라 달라지므로, 모든 머신에 같은 버전이 있다고 가정하지 말고 파이프라인 실행 전에 xcrun simctl list runtimes로 확인해야 합니다. 여러 작업을 병렬로 실행한다면 상태가 공유되지 않도록 기기 이름에도 작업 번호를 포함해야 합니다.

녹화의 목적은 실패 타임라인을 보완하는 것이지 로그를 대체하는 것이 아닙니다. 영상은 “UI에서 먼저 무슨 일이 일어났는가”를 보여 주고, 로그와 xcresult는 “테스트 프레임워크가 무엇을 기록했는가”를 알려 줍니다.

녹화 프로세스를 안전하게 종료하기

simctl io recordVideo는 계속 실행되므로 스크립트에서 해당 PID를 저장해야 합니다. 테스트가 끝난 직후 강제 종료 신호를 보내지 마세요. 먼저 INT를 보내 도구가 비디오 컨테이너의 인덱스를 모두 기록하도록 한 다음, 프로세스가 종료될 때까지 기다려야 합니다.

ARTIFACTS="${PWD}/artifacts"
VIDEO="${ARTIFACTS}/ui-test.mp4"
RESULT="${ARTIFACTS}/UITests.xcresult"
LOG="${ARTIFACTS}/xcodebuild.log"

mkdir -p "$ARTIFACTS"
rm -rf "$RESULT"
rm -f "$VIDEO" "$LOG"

xcrun simctl io "$UDID" recordVideo \
  --codec=h264 \
  --force "$VIDEO" &
RECORDER_PID=$!

finish_recording() {
  if kill -0 "$RECORDER_PID" 2>/dev/null; then
    kill -INT "$RECORDER_PID"
    wait "$RECORDER_PID" || true
  fi
}

trap finish_recording EXIT INT TERM

H.264는 일반적으로 브라우저나 이슈 관리 시스템의 첨부 파일로 미리 보기 편합니다. 팀에서 이후 프레임 단위 분석이 필요하다면 산출물 시스템과의 호환성을 확인한 뒤 다른 코덱으로 변경할 수 있습니다. 다만 동일한 파이프라인에서 여러 형식을 혼용하면 뷰어와 보관 정책이 예측하기 어려워지므로 피해야 합니다.

실제 테스트 종료 코드 보존하기

녹화는 별도의 보조 프로세스이므로 xcodebuild의 결과를 가려서는 안 됩니다. 가장 안정적인 방법은 오류 발생 시 즉시 종료하는 동작을 잠시 비활성화하고 테스트 종료 코드를 별도로 저장한 뒤 녹화를 정상적으로 마치는 것입니다. tee로 로그를 화면에 표시한다면 파이프라인 안에서 xcodebuild의 종료 상태를 읽어야 하며, tee의 성공 상태를 잘못 사용해서는 안 됩니다.

set +e
xcodebuild test \
  -workspace App.xcworkspace \
  -scheme AppUITests \
  -destination "platform=iOS Simulator,id=${UDID}" \
  -resultBundlePath "$RESULT" \
  >"$LOG" 2>&1
TEST_STATUS=$?
set -e

finish_recording
trap - EXIT INT TERM

if [ "$TEST_STATUS" -eq 0 ]; then
  rm -f "$VIDEO"
  exit 0
fi

exit "$TEST_STATUS"

여기서는 테스트가 실패해도 즉시 종료하지 않도록 의도적으로 구성했습니다. 녹화 프로세스가 마무리 작업을 완료해야 하기 때문입니다. resultBundlePath에는 작업마다 독립된 경로를 사용하고, 실행 전에 기존 디렉터리를 삭제해야 합니다. 그렇지 않으면 이전 결과가 이번 실패 결과와 섞일 수 있습니다.

파일 존재 여부가 아닌 영상 자체 검증하기

크기가 0바이트인 파일, 컨테이너 헤더만 있는 짧은 파일, 강제로 중단된 녹화 파일은 진단에 도움이 되지 않습니다. 보관하기 전에 최소한 파일 크기를 확인하고 시스템 미디어 도구로 재생 시간을 읽어야 합니다. 테스트가 시작되자마자 실패했다면 영상이 매우 짧은 것이 정상일 수 있으므로, 재생 시간 기준을 지나치게 높게 설정해서는 안 됩니다.

확인 항목 권장 작업 실패 시 처리
파일 존재 여부 test -f 로그를 보관하고 녹화 누락으로 표시
파일이 비어 있지 않음 test -s 녹화 PID와 디스크 공간 확인
재생 시간 읽기 가능 미디어 메타데이터 조회 손상된 파일로 간주하고 빈 껍데기 파일은 업로드하지 않음
기기 일치 여부 기록된 UDID 비교 작업을 중단하고 잘못된 기기 정리
테스트 결과 번들 xcresult 디렉터리 확인 원본 로그를 대체 자료로 보관

UDID, 테스트 시작 시간, 녹화 경로를 일반 텍스트 목록에 기록해 영상과 함께 보관할 수 있습니다. 액세스 자격 증명, 전체 환경 변수 또는 민감 정보가 제거되지 않은 명령줄을 목록에 기록하지 마세요. 영상에도 알림, 테스트 계정 이름 또는 비즈니스 데이터가 노출될 수 있으므로 테스트 픽스처에는 별도의 비민감 샘플을 사용해야 합니다.

병렬 실행, 시간 초과, 잔류 프로세스 처리하기

각 작업은 독립된 시뮬레이터, 결과 디렉터리, 녹화 파일 이름을 사용해야 합니다. booted, 고정된 artifacts/ui-test.mp4, 공용 DerivedData 디렉터리를 공유하면 병렬 작업이 서로의 파일을 덮어쓸 수 있습니다. 작업별 디렉터리는 파이프라인에서 제공하는 고유 번호로 생성하고, 종료 시 성공한 작업의 임시 파일을 삭제할 수 있습니다.

외부 타임아웃 도구가 테스트를 종료할 때도 정리 함수가 실행될 기회를 확보해야 합니다. 먼저 테스트 프로세스에 처리 가능한 종료 신호를 보내고, trap이 녹화를 마무리할 수 있도록 몇 초간 기다린 뒤 마지막에 강제 정리를 수행하세요. 다음 작업을 시작하기 전에 부모 프로세스가 이미 종료된 simctl io 녹화 프로세스가 남아 있는지 확인할 수 있지만, 광범위한 killall은 사용하지 마세요. 같은 머신에서 실행 중인 다른 작업까지 잘못 종료할 수 있습니다.

안정적인 보관 산출물은 일반적으로 실패 영상, xcresult 결과 번들, 원본 빌드 로그의 세 가지로 충분합니다. 세 항목은 동일한 작업 번호로 이름을 지정하고 보존 기간도 동일하게 설정해야 합니다. 그러면 실패 목록에서 특정 작업을 열어 먼저 영상으로 UI 상태를 확인하고, 결과 번들에서 단언과 첨부 파일을 찾은 다음, 마지막으로 로그에서 명령, 대상 기기, 종료 코드를 대조할 수 있습니다. 이를 통해 빠짐없이 충분하면서도 불필요하게 과도하지 않은 증거 체계를 구성할 수 있습니다.

자주 묻는 질문

왜 booted 대신 UDID를 사용해야 하나요?

병렬 작업에서는 여러 시뮬레이터가 동시에 실행될 수 있습니다. 명시적 UDID를 사용해야 부팅, 테스트, 녹화, 정리가 같은 장치를 대상으로 합니다.

녹화 파일이 재생되지 않는 이유는 무엇인가요?

프로세스를 강제 종료하면 동영상 컨테이너 인덱스 기록이 중단될 수 있습니다. INT 신호를 보내고 종료를 기다린 뒤 파일을 검증해야 합니다.

성공한 테스트 영상도 보관해야 하나요?

대부분 필요하지 않습니다. 성공 시 영상을 삭제하고 실패 시에만 영상, 로그, xcresult를 함께 보관하는 편이 효율적입니다.

Debug M4

다음 빌드를 전용 Apple Silicon 물리 노드에서 실행

대여 기간과 노드 리전을 선택하고 Mac Mini M4, 16GB RAM, 256GB SSD 및 결제할 USD 금액을 확인한 뒤 주문을 제출하세요.

클라우드 Mac 지금 대여