본문으로 건너뛰기

모바일 앱 안정성을 위한 계층형 테스트 전략: Gusto의 iOS 테스트 자동화 사례

Building Resilient Mobile Apps: A Layered Testing Strategy for Long-Term Stability

engineering.gusto.com

핵심 요약

  1. 기존의 느리고 불확실한 UI 테스트 중심 구조에서 탈피하여, 유닛 테스트를 기반으로 스냅샷과 UI 테스트를 쌓아 올리는 테스트 피라미드 전략을 채택하여 안정성을 확보했다.
  2. MVVM 및 Coordinator 아키텍처를 활용한 프로토콜 기반 모킹으로 유닛 테스트의 결정성을 확보하고, swift-snapshot-testing을 도입해 시각적 회귀를 방지하는 체계를 구축했다.
  3. 네트워크 의존성을 제거한 API 스터빙과 Bitrise의 병렬 실행 및 캐싱 기술을 결합하여 전체 테스트 수행 시간을 75분에서 39분으로 단축하고 개발 피드백 루프를 대폭 개선했다.

도입

Gusto의 iOS 팀은 매주 릴리스를 진행하면서 기존 자동화 테스트의 낮은 커버리지와 긴 피드백 시간으로 인해 수동 검증에 의존해야 하는 한계에 직면했습니다. 특히 현지화 문자열 오류가 자동화에서 걸러지지 않아 릴리스 주기를 놓치는 사건을 계기로, 팀은 테스트 피라미드 모델에 기반한 계층형 테스트 전략을 재구축했습니다. 이는 단순한 테스트 추가가 아니라 아키텍처와 인프라를 아우르는 체계적인 접근 방식입니다.

상세 요약

테스트 피라미드 기반의 계층화

Gusto는 기존의 비효율적인 테스트 구조를 개선하기 위해 테스트 피라미드 모델을 도입했다. 하단에는 빠르고 격리된 유닛 테스트를 배치하고, 중간층에는 컴포넌트 수준의 스냅샷 테스트를, 최상단에는 핵심 사용자 흐름을 검증하는 UI 테스트를 배치하는 방식이다. 이를 통해 과거 UI 테스트에 과도하게 의존하여 발생했던 속도 저하와 불안정성 문제를 해결했다.

MVVM + Coordinator 아키텍처와 유닛 테스트

유닛 테스트의 효율성을 극대화하기 위해 MVVM과 Coordinator 아키텍처의 특성을 활용했다. 비즈니스 로직을 담당하는 ViewModel과 네비게이션을 관리하는 Coordinator는 UI 레이어와 분리되어 있어 독립적인 테스트가 용이하다.

  • 프로토콜 기반 모킹: 실제 의존성 대신 프로토콜을 주입하여 테스트 환경을 제어한다. 이를 통해 네트워크 상태나 외부 데이터와 무관하게 비즈니스 로직의 정확성만 검증할 수 있다.
  • 결정성 확보: 모의 객체(Mock)를 사용하여 테스트 결과가 항상 일정하게 나오도록 설계했다. 이는 테스트 신뢰도를 높이는 핵심 요소다.
  • 빠른 피드백: 유닛 테스트는 앱 전체를 실행할 필요가 없으므로 수천 개의 테스트도 매우 짧은 시간 안에 완료된다.

swift-snapshot-testing을 통한 시각적 회귀 방지

디자인 시스템 변경이나 iOS 버전 업그레이드 시 발생하는 의도치 않은 UI 변경을 감지하기 위해 swift-snapshot-testing을 도입했다.

  • 작동 원리: 뷰를 렌더링하여 참조 이미지와 픽셀 단위로 비교한다. 폰트, 색상, 레이아웃의 미세한 변화도 즉시 감지하여 개발자에게 알린다.
  • Git LFS 활용: 스냅샷 이미지 파일로 인해 저장소 용량이 비대해지는 문제를 방지하기 위해 Git LFS(Large File Storage)를 사용했다. 실제 이미지는 별도 저장소에 보관하고 Git에는 포인터 파일만 남겨 저장소 성능을 유지했다.

XCUITest의 안정성을 높이는 API 스터빙

UI 테스트의 고질적인 문제인 불안정성(Flakiness)을 해결하기 위해 실제 네트워크 호출을 완전히 제거했다.

  • StubbedURLSession: 프로토콜 주입을 통해 네트워크 응답을 제어하는 스터브를 사용한다. REST와 GraphQL 요청 모두에 대해 미리 정의된 데이터를 반환하도록 설정하여 네트워크 지연이나 서버 장애의 영향을 받지 않도록 했다.
  • 핵심 흐름 집중: 모든 기능을 UI 테스트로 커버하는 대신 로그인, 시간 추적, 금융 작업 등 비즈니스 임팩트가 큰 흐름에 우선순위를 두어 효율을 높였다.

Bitrise CI를 활용한 파이프라인 최적화

테스트 실행 효율을 높이기 위해 Bitrise CI 환경에서 이원화된 빌드 전략을 운영한다.

  • PR 빌드: 개발자가 코드를 제출할 때마다 유닛 테스트와 스냅샷 테스트만 실행하여 빠른 피드백을 제공한다. 파생 데이터(Derived Data) 캐싱을 통해 재컴파일 시간을 최소화했다.
  • 나이트리 빌드: 매일 밤 전체 테스트 슈트를 실행한다. 테스트 타겟을 여러 러너에 분산하여 병렬로 실행함으로써 기존 75분 걸리던 작업을 39분으로 단축했다.
  • 가시성 확보: 슬랙 모니터를 통해 간헐적 실패와 빌드 실패를 실시간으로 공유한다. 실패하는 테스트는 무시하지 않고 버그로 취급하여 즉시 수정하는 문화를 정착시켰다.

결론

계층형 전략 도입 후 유닛 테스트 커버리지가 상승하고 전체 테스트 수행 시간이 절반 이하로 단축되는 실질적인 성과를 거두었습니다. 특히 네트워크 스터빙을 통한 UI 테스트의 결정성 확보와 Git LFS를 활용한 스냅샷 관리, 그리고 슬랙 기반의 모니터링 체계는 테스트 슈트의 신뢰도를 높이는 핵심 요소입니다. 이는 모바일 개발 팀이 속도와 안정성 사이에서 균형을 잡기 위해 반드시 고려해야 할 실무적 지침을 제공합니다.