GitHub Actions의 matrix에 테스트 항목을 2개 정의하면 각각 별도 작업으로 확장됩니다. 다만 실제로 동시에 실행되는 작업 수는 비어 있는 Runner 수를 넘을 수 없습니다. 따라서 GitHub Actions iOS UI 테스트 분할은 먼저 Test Plan으로 안정적인 경계를 만들고, 그다음 여러 독립 원격 맥으로 라우팅해야 효과가 있습니다. Runner가 한 대뿐이면 matrix는 작업을 여러 개 만들 뿐, 노드 간 병렬 실행을 만들지 못합니다. GitHub Actions의 작업 실행 구조도 이 차이를 전제로 설명합니다.

이 글은 다음 사람을 위한 안내서입니다.

  • iOS 테스트 엔지니어: 커지는 XCTest UI 테스트를 독립 실행 가능한 묶음으로 나누려는 분
  • DevOps 엔지니어: matrix, Runner 라벨, 동시성 제한과 결과 취합을 구성하려는 분
  • 개발 책임자: 대기열, 실패 재현성, 노드 활용률을 보고 원격 맥 추가 여부를 판단하려는 분
01

시작 전에 전체 테스트의 기준선을 고정합니다

처음부터 분할하지 마십시오. 먼저 전체 UI 테스트를 한 번 실행하고 아래 항목을 같은 커밋 기준으로 저장합니다.

  • 테스트가 시작된 시각과 끝난 시각
  • 빌드와 테스트의 소요 구간
  • 테스트별 실행 순서와 실패 위치
  • Runner 대기 시간
  • Simulator 준비 시간
  • xcresult, 콘솔 로그, 실패 스크린샷
  • 테스트 계정과 외부 환경의 상태

이 기록이 있어야 테스트 자체가 느린지, Runner가 부족한지, Simulator가 불안정한지 구분할 수 있습니다. Apple은 테스트 실행과 결과 해석 과정에서 테스트 결과 패키지를 사용하도록 안내합니다. 기준선은 Apple의 테스트 실행 및 결과 해석 문서와 함께 확인하십시오.

특히 다음 세 가지를 섞어 세면 안 됩니다.

구분 실제 의미 늘렸을 때 생기는 변화
GitHub Actions 작업 동시성 workflow가 만든 독립 작업의 실행 수 작업이 여러 Runner로 배정될 기회가 늘어남
여러 원격 맥의 동시 실행 실제 macOS 노드 수 서로 다른 노드에서 분할을 동시에 실행할 수 있음
Xcode 내부 병렬 실행 한 노드의 Simulator 또는 테스트 프로세스 병렬화 단일 노드의 자원 소비와 충돌 가능성이 커짐

Swift Testing의 프로세스 내부 병렬 실행도 별도 층입니다. 이것을 Xcode Simulator 병렬 실행이나 여러 GitHub Actions 작업과 같은 지표로 기록하면 잘못된 확장 결정을 내리기 쉽습니다.

첫 기준선의 중단 조건

전체 실행 결과가 매번 달라지면 분할을 중지합니다. 공유 계정, 고정되지 않은 서버 데이터, 테스트 순서 의존성이 남아 있기 때문입니다. 반대로 실패 위치와 결과 패키지가 안정적으로 재현되면 다음 단계로 넘어갑니다.

02

첫 분할은 파일 수가 아니라 의존성으로 만듭니다

Xcode Test Plans, 테스트 Target, Suite, only-testing은 분할 경계를 만드는 도구입니다. 파일을 같은 개수로 나누는 방식은 빠르게 보이지만, 로그인이나 데이터 초기화가 한쪽에 몰리면 실제 실행 시간은 균형을 잃습니다.

다음 순서로 나누십시오.

  1. 전체 테스트를 기능 흐름별로 목록화합니다.
  2. 로그인, 결제 모의 환경, 푸시 권한처럼 공유 상태를 표시합니다.
  3. 앞 단계의 결과가 다음 테스트 입력이 되는 흐름을 하나의 묶음으로 둡니다.
  4. 서로 독립적인 기능 묶음을 Test Plan 구성이나 only-testing 선택 범위로 정의합니다.
  5. 각 분할에 고정 이름, 입력 데이터, 담당 범위, 재현 명령을 지정합니다.
  6. 모든 분할을 실행한 결과와 전체 실행 결과를 비교합니다.
  7. 누락되거나 두 번 실행된 테스트가 있으면 분할을 되돌립니다.

Apple은 피드백 시간을 개선하기 위해 테스트를 목적과 실행 특성에 따라 조직하는 방식을 설명합니다. 테스트 구성과 피드백 개선에 관한 공식 안내를 기준으로 Suite와 Test Plan의 역할을 확인하십시오.

분할 기준 장점 위험 권장 판단
기능 영역 실패 위치를 찾기 쉬움 한 영역에 무거운 흐름이 몰릴 수 있음 첫 분할에 적합
파일 수 구성은 빠름 실행 시간과 의존성을 반영하지 못함 임시 시험 외에는 주의
로그인과 공유 상태 상태 충돌을 줄임 묶음이 커질 수 있음 같은 분할에 유지
테스트 시간 실행 시간 균형에 유리 측정값이 커밋마다 달라질 수 있음 기준선 확보 후 사용

주의: 분할 이름만 바꾼다고 격리가 생기지 않습니다. Simulator, DerivedData, 결과 패키지, 임시 폴더, 포트와 테스트 계정까지 작업별로 분리해야 합니다.

03

matrix 작업을 원격 맥에 처음 연결합니다

각 분할을 matrix 항목으로 만들면 workflow는 독립 작업을 생성할 수 있습니다. 그러나 max-parallel은 허용 상한일 뿐입니다. 실제 실행 수는 사용 가능한 자체 호스팅 Runner와 라벨 조건에 달려 있습니다. GitHub Actions workflow 문법 문서에서 matrix와 동시성 설정을 확인하십시오.

예시의 이름과 경로는 실제 값으로 바꾸지 않고 자리표시자로 유지합니다.

strategy:
  matrix:
    test_group:
      - "<GROUP_A>"
      - "<GROUP_B>"
  max-parallel: 2

runs-on:
  - self-hosted
  - "<RUNNER_LABEL>"

자체 호스팅 Runner 라벨은 필요한 Xcode, Simulator, 프로젝트 권한을 가진 노드에만 붙여야 합니다. 라벨을 잘못 지정하면 작업이 실행되지 않거나 다른 환경으로 갈 수 있습니다. 자체 호스팅 Runner 라벨 사용법을 확인한 뒤, 노드별 라벨을 고정하십시오.

설정 요소 확인할 내용 잘못 구성했을 때
matrix 항목 각 항목이 독립적인 테스트 범위인지 누락과 중복이 발생
max-parallel 허용할 최대 작업 수인지 과도한 동시 실행 유발
Runner 라벨 Xcode와 Simulator 조건이 맞는지 작업 대기 또는 오배정
concurrency 같은 브랜치 작업을 취소할지 여부 실행 중인 검증이 갑자기 중단
결과 경로 작업마다 고유한지 xcresult가 서로 덮어쓰기

빌드 경로는 두 가지로 나뉩니다.

  • 각 분할이 매번 직접 빌드하는 방식: 구성이 단순하지만 빌드가 반복됩니다.
  • build-for-testing으로 테스트 산출물을 만든 뒤 분할 작업에 전달하는 방식: 빌드 중복은 줄일 수 있지만 보관, 전달, 환경 일치 검증이 필요합니다.

프로젝트가 작을 때는 첫 번째 방식으로 기준선을 만들고, 빌드 시간이 병목으로 확인된 뒤 두 번째 방식을 검토하는 편이 안전합니다. 처음부터 산출물 전달까지 넣으면 실패 원인이 테스트인지 전달 과정인지 분리하기 어렵습니다.

04

첫 병렬 실행은 노드 격리부터 검증합니다

두 분할을 동시에 실행하더라도 같은 자원을 쓰면 독립 실행이 아닙니다. 다음 항목을 작업 식별자에 연결하십시오.

  • Simulator 이름 또는 destination
  • DerivedData 경로
  • xcresult 저장 경로
  • 임시 파일과 캐시 경로
  • 테스트 포트
  • 테스트 계정과 초기 데이터
  • 실패 스크린샷 경로

첫 시험에서는 한 번에 하나의 동시성 층만 바꾸십시오. 먼저 여러 작업을 한 원격 맥에서 실행하고, 다음 실행에서 여러 원격 맥으로 확장하는 식입니다. 이렇게 해야 자원 부족과 테스트 코드의 공유 상태를 분리할 수 있습니다.

조건에 따른 실행 선택

  • 분할 간 계정과 데이터가 완전히 분리되어 있으면 한 노드의 낮은 병렬성부터 선택합니다.
  • Simulator 메모리와 저장 장치 사용량이 급증하면 내부 병렬성을 줄이고 여러 원격 맥으로 되돌립니다.
  • Runner 대기 시간이 실행 시간보다 길면 matrix를 더 늘리지 말고 사용 가능한 노드를 먼저 확인합니다.
  • 분할마다 독립 Runner가 있고 결과가 안정적이면 다중 노드 matrix를 선택합니다.
  • 실패가 순서나 공유 상태와 관련되면 해당 묶음을 직렬로 되돌립니다.
  • 출시 핵심 테스트가 병렬 결과와 다르면 직렬 기준선 또는 이중 실행을 유지합니다.

한 대의 원격 맥에서 동시에 몇 개의 Simulator를 실행할 수 있는지는 문서의 고정 숫자로 결정되지 않습니다. 실제 값은 대상 프로젝트와 노드 자원에 따라 달라집니다. 따라서 낮은 동시성으로 시작하고 시스템 자원, 테스트 로그, 실패 화면을 함께 봐야 합니다. Apple의 병렬 테스트 관련 공식 문서도 실행 결과와 환경을 함께 해석하는 접근을 전제로 합니다.

05

결과 취합은 성공 여부보다 실패 원인을 보존합니다

각 matrix 작업은 최소한 다음 산출물을 별도로 올려야 합니다.

  • xcresult
  • 콘솔 로그
  • 실패 스크린샷
  • 분할 목록
  • 사용한 Simulator와 커밋 식별자
  • 테스트 계정 또는 데이터 준비 결과

취합 작업은 먼저 모든 분할이 도착했는지 확인해야 합니다. 하나의 결과가 빠졌는데 나머지 성공만으로 workflow를 통과시키면 실제 검증 범위가 줄어듭니다.

실패는 세 종류로 나누십시오.

  1. 인프라 실패: Runner 연결, Simulator 부팅, 디스크, 권한 문제
  2. 테스트 실패: 실제 assertion 또는 화면 동작 검증 실패
  3. 불안정 실패: 같은 커밋에서 결과가 반복되지 않는 실패

재시도는 불안정성을 확인하는 도구이지, 첫 실패를 삭제하는 도구가 아닙니다. 첫 실행의 실패 기록과 재시도 결과를 함께 보관하십시오. 불안정 테스트는 격리 목록으로 이동하고, 테스트 코드와 환경 중 어느 쪽이 책임지는지 지정해야 합니다.

커버리지도 단순히 백분율을 더하면 안 됩니다. 여러 결과를 병합할 수 있는지, 같은 파일과 테스트가 중복 집계되는지, 사용하는 공식 도구가 무엇인지 먼저 확인해야 합니다. 결과 패키지를 보존하는 방식은 Apple의 테스트 결과 문서와 프로젝트의 검증 절차를 함께 맞춰야 합니다.

06

자주 묻는 실행 판단

FAQ는 분할 구성을 실제 workflow에 연결할 때 자주 생기는 판단을 정리합니다. 작업 수와 실제 용량을 혼동하지 않는 것이 핵심입니다.

07

첫 주에는 단일 노드와 다중 노드를 함께 비교합니다

처음부터 장기 구성을 확정하지 마십시오. 실제 Pull Request를 기준으로 단일 노드 직렬, 단일 노드 내부 병렬, 다중 노드 matrix를 차례로 비교합니다.

관찰 항목 기록 방법 다음 판단
전체 피드백 시간 첫 작업 대기부터 마지막 결과까지 기록 대기와 실행을 분리
대기 시간 Runner 배정 전 시간을 별도 기록 노드 부족 여부 확인
분할 불균형 가장 긴 분할과 짧은 분할 비교 묶음 재구성 검토
실패 재현률 같은 커밋의 반복 결과 비교 불안정 테스트 격리
노드 활용 상태 CPU, 메모리, 저장 장치와 로그 확인 내부 병렬 또는 노드 추가 판단
결과 일치성 직렬 기준선과 matrix 결과 비교 출시 전 이중 검증 유지 여부 결정

가장 긴 분할이 계속 전체 시간을 지배하면 다시 나누거나 묶음을 재구성합니다. 반대로 Runner 대기가 가장 큰 비중을 차지하면 matrix 수를 더 늘리지 말고 원격 맥 노드를 추가할지 검토해야 합니다.

출시 직전에는 직렬 기준선이나 정기적인 전체 테스트를 남겨 두십시오. 병렬 결과가 안정적으로 일치한 뒤에야 직렬 실행 빈도를 줄이는 것이 좋습니다. 롤백할 때는 기존 Test Plan, 단일 Runner 경로, 전체 결과 취합 경로를 즉시 복구할 수 있어야 합니다.

이번 방식에 맞는 노드가 필요한지 판단하려면 KVMNODE의 원격 맥 환경에서 접속 방식과 운영 조건을 먼저 확인하십시오. Xcode와 Simulator가 실제로 필요한지 확인하는 과정은 원격 맥의 Xcode와 Simulator 검수 안내와 함께 비교하면 좋습니다.

현재 한 대의 Mac mini나 단일 자체 호스팅 Runner만 사용하는 방식은 초기 검증에는 단순하지만, 작업이 몰리면 대기열이 생기고 한 노드의 Simulator 장애가 전체 흐름을 막습니다. 반대로 여러 원격 맥을 직접 관리하면 노드 격리, 접근 권한, 결과 보관과 비용을 함께 관리해야 합니다. 단기 시험이나 특정 기간의 UI 테스트 분산이 목적이라면 KVMNODE의 원격 맥을 임시 테스트 노드로 사용해 단일 노드 기준선과 두 분할 결과를 먼저 비교하는 편이 현실적입니다. 단, 장기간 고정 부하가 계속되거나 물리 장치 연결이 필수라면 직접 구매한 Mac이 더 적합할 수 있습니다.

핵심은 matrix 작업 수가 아닙니다. 안정적인 Test Plan 경계, 실제로 비어 있는 Runner, 충돌 없는 Simulator 환경, 첫 실패를 보존하는 결과 취합이 함께 맞아야 GitHub Actions iOS UI 테스트 분할이 운영 가능한 CI가 됩니다.