모바일 앱 테스팅은 애플리케이션이 올바르게 작동하고, 충돌하지 않으며, 요구사항을 충족하는지 확인하는 프로세스입니다. Software Testing Help (2025)에 따르면, 자동화된 테스팅은 수동 테스팅에 비해 회귀 검사 시간을 70~80% 단축시킵니다. 이 글에서는 테스팅 레벨, iOS 및 Android 도구, TDD 및 BDD, 그리고 CI/CD에 대해 다룹니다.
핵심 요점
유닛 테스트는 모바일 앱 테스팅의 기초입니다. 코드의 가장 작은 단위(단일 함수, 메서드 또는 클래스)를 시스템의 나머지 부분에서 격리하여 검증합니다. 모바일 개발에서 유닛 테스트는 JUnit(Android)과 XCTest(iOS)로 작성됩니다. 좋은 유닛 테스트는 빠르고, 독립적이며, 반복 가능해야 합니다 — 네트워크, 데이터베이스 또는 UI 구성 요소에 의존해서는 안 됩니다. 격리를 위해 테스트 더블(목, 스텁, 페이크)이 사용됩니다.
Mockito(Java/Kotlin)와 MockK(Kotlin 우선)는 Android에서 목 객체를 생성하는 인기 라이브러리입니다. iOS에서는 OCMock, Cuckoo 또는 수동 프로토콜이 사용됩니다. 규칙: 유닛 테스트는 비즈니스 로직과 데이터 모델을 다뤄야 합니다. UI 테스트는 유닛 테스트를 중복해서는 안 됩니다 — UI 테스트는 사용자와 인터페이스 간의 상호작용을 검증합니다.
통합 테스트는 컴포넌트 간의 상호작용을 검증합니다: 데이터베이스와 리포지토리, API 서비스와 ViewModel, 화면 간 탐색. 유닛 테스트와 달리 통합 테스트는 실제 또는 실제에 가까운 종속성(예: 인메모리 데이터베이스 또는 목 서버)을 사용합니다. Robolectric은 에뮬레이터 없이 JVM에서 Android 테스트를 실행하는 프레임워크로, 통합 테스트를 10배 가속화합니다.
스냅샷 테스트(골든 테스트)는 렌더링된 UI 컴포넌트를 참조 이미지(스냅샷)와 비교하는 특수한 유형의 통합 테스트입니다. 외관이 변경되면 테스트가 실패하여 개발자가 무엇이 변경되었는지 확인할 수 있습니다. Facebook SnapshotTestCase(iOS)와 Shot(Android)은 스냅샷 테스트의 인기 도구입니다.
E2E 테스트(엔드 투 엔드)는 시작부터 끝까지 전체 사용자 시나리오를 검증합니다: 앱 실행, 로그인, 작업 수행, 결과 확인. UI 테스트는 인터페이스에 초점을 맞춘 E2E의 하위 집합입니다. 도구: Espresso(Android), XCUITest(iOS), Detox(React Native). E2E 테스트는 가장 느리므로 CI에서 별도로 실행됩니다 — 일반적으로 야간 빌드에서.
XCTest는 Apple의 모바일 앱 유닛 테스팅 내장 프레임워크입니다. XCTestRunner는 시뮬레이터 또는 실제 기기에서 테스트를 실행합니다. 테스트는 XCTestCase를 상속받으며, 준비와 정리를 위해 setUp과 tearDown을 포함합니다. XCTest에는 어설션을 위한 XCTAssert(XCTAssertEqual, XCTAssertNil, XCTAssertTrue)와 비동기 작업 대기를 위한 XCTWaiter가 포함됩니다.
간단한 XCTest 테스트 예제: User 모델 생성, 초기화 정확성, 이름 형식 지정 및 나이 계산 확인. Xcode의 코드 커버리지는 테스트로 커버된 코드 라인을 보여줍니다 — 상용 프로젝트의 목표: 비즈니스 로직의 최소 70~80% 커버리지. XCTest는 xcodebuild test를 통해 Xcode Server 및 CI 시스템과 통합됩니다.
XCUITest는 Apple의 UI 테스팅 프레임워크입니다. 접근성 식별자를 통해 작동합니다: XCUIElementQuery는 레이블, 식별자 또는 유형별로 버튼, 입력 필드, 테이블을 찾습니다. XCUITest는 작업 시퀀스를 기록(레코드/플레이백)하고 테스트 코드를 생성합니다. 중요: 안정적인 테스트 작동을 위해 모든 UI 요소에 accessibilityIdentifier가 있어야 합니다.
JUnit은 Java/Kotlin에서 모바일 앱의 단위 테스팅을 위한 기본 프레임워크입니다. Android에서는 JUnit 4(최신 안정 버전 4.13.2)와 새 프로젝트용 JUnit 5가 사용됩니다. Mockito는 목 객체를 생성하는 라이브러리입니다: when(mock.method()).thenReturn(value) — 테스트 대상 클래스를 종속성에서 격리하는 표준 패턴입니다.
Android용 JUnit 테스트 예제:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class LoginViewModelTest {
@Mock
AuthRepository authRepository;
@Test
public void login_emptyEmail_returnsError() {
LoginViewModel vm = new LoginViewModel(authRepository);
String result = vm.login("", "password123");
assertEquals("Email cannot be empty", result);
verify(authRepository, never()).authenticate(any());
}
}
Espresso는 Google의 Android UI 테스트 프레임워크입니다. Espresso는 자동으로 UI 스레드와 동기화됩니다: onView(withId(R.id.button)).perform(click()).check(matches(isDisplayed())). Espresso는 내장된 유휴 상태 대기 덕분에 작성하기 쉽고 안정적입니다. UI Automator는 시스템 요소(권한 대화상자, 알림 창)와 상호작용할 수 있는 크로스 애플리케이션 테스트 프레임워크입니다.
Detox는 Wix의 React Native 모바일 앱 테스팅용 그레이박스 E2E 프레임워크입니다. Detox는 내부적으로 Espresso(Android)와 XCUITest(iOS)를 사용하여 단일 테스트 코드베이스에서 두 플랫폼 모두에서 작동합니다. Detox는 앱이 유휴 상태(애니메이션, 네트워크 요청, 타이머 없음)가 될 때까지 자동으로 기다린 후 다음 작업을 수행합니다.
Appium은 Android, iOS, 웹 및 하이브리드 앱을 지원하는 범용 크로스 플랫폼 프레임워크입니다. Appium은 WebDriver 프로토콜을 사용하며 모든 프로그래밍 언어(Java, Python, JS, Ruby)를 지원합니다. Appium Server는 HTTP 서버로 작동하여 명령을 네이티브 UI Automator / XCUITest 명령으로 변환합니다. Appium의 주요 단점은 속도입니다: 테스트가 네이티브 Espresso나 XCUITest보다 느리게 실행됩니다.
| 기준 | iOS | Android |
|---|---|---|
| 유닛 테스트 | XCTest | JUnit 4/5 + Mockito |
| UI 테스트 | XCUITest | Espresso, UI Automator |
| 스냅샷 테스트 | FBSnapshotTestCase | Shot, Roborazzi |
| 제스처 자동화 | XCUIGesture | UiAutomator touch |
| 코드 커버리지 | Xcode Code Coverage | Jacoco |
| CI 통합 | xcodebuild test | Gradle connectedCheck |
TDD는 구현 코드 전에 테스트를 작성하는 모바일 앱 테스팅 방법론입니다. Red-Green-Refactor 주기: (1) 실패하는 테스트 작성(Red), (2) 테스트를 통과시키는 최소 코드 작성(Green), (3) 테스트 통과를 유지하며 코드 리팩터링. TDD는 새로운 기능에 대해 100% 테스트 커버리지와 깔끔한 아키텍처를 제공합니다. 테스트가 요구사항의 첫 번째 명세이기 때문입니다.
BDD는 TDD의 확장으로, Given-When-Then 형식의 자연어로 테스트를 작성합니다. Given(컨텍스트) — When(액션) — Then(예상 결과). BDD 테스트는 개발자, 테스터, 분석가, 클라이언트 등 모든 팀 구성원이 이해할 수 있습니다. Mock vs Stub vs Fake: Mock은 상호작용(메서드 호출 여부)을 검증하고, Stub은 고정 데이터를 반환하며, Fake는 단순화된 작동 구현(예: 인메모리 DB)입니다. IT Sectr에서는 중요 비즈니스 로직에 TDD를, 승인 시나리오에 BDD를 사용합니다.
테스트 더블은 테스트에서 실제 종속성을 대체하는 객체의 일반적인 이름입니다. 네 가지 유형이 있습니다: Dummy(매개변수 채우기용, 사용되지 않음), Stub(지정된 값 반환), Spy(검증을 위해 호출 기록), Mock(예상 호출 미리 정의). 차이점을 이해하는 것이 올바른 테스트 설계에 매우 중요합니다.
CI/CD — 지속적 통합 및 지속적 전달: 모든 코드 변경 시 모바일 앱을 자동으로 빌드하고 테스트하는 방식입니다. 모바일 개발에서 CI/CD 파이프라인에는 다음이 포함됩니다: 린팅, 유닛 테스트, 통합 테스트, APK/IPA 빌드 및 UI 테스트. GitHub Actions와 Bitrise는 모바일 CI/CD의 인기 플랫폼입니다. 테스트는 빠르게 실행되어야 합니다: 유닛 테스트 1~2분, 통합 테스트 5~10분, UI 테스트 15~30분.
Device Farm은 테스트용 실제 기기 팜입니다. Firebase Test Lab(Android)과 Xcode Cloud(iOS)는 수백 개의 기기 모델에 대한 클라우드 액세스를 제공합니다. Device Farm은 에뮬레이터에서 보이지 않는 문제를 발견합니다: 다양한 화면 크기, 오래된 기기에서의 성능, 호환성 문제. IT Sectr에서는 정기적으로 Android용 Firebase Test Lab과 iOS용 Xcode Cloud를 사용합니다.
자주 묻는 질문
상용 프로젝트의 경우 비즈니스 로직의 최소 70~80% 커버리지. UI 코드는 커버하기 어렵습니다 — 50%면 충분합니다. 중요한 것은 백분율이 아닌 테스트 품질입니다: 중요 시나리오, 경계 사례 및 오류 처리를 테스트하세요.
Mock은 상호작용을 검증합니다 — 특정 매개변수로 특정 메서드가 호출되었는지 여부. Stub은 미리 정의된 데이터를 반환합니다. Mock은 동작을 검증하고, Stub은 상태를 검증합니다.
네, 하지만 중요 시나리오에만 해당합니다: 로그인, 등록, 주문 완료, 결제. UI 테스트는 느리고 취약합니다 — 모든 화면에 테스트를 작성하지 마세요. 사용자의 E2E 시나리오에 집중하세요.
스냅샷 테스트(골든 테스트)는 렌더링된 UI 컴포넌트를 참조 이미지와 비교합니다. 외관이 변경되면(글꼴, 패딩, 색상) 테스트가 실패하여 개발자가 변경이 의도적인지 확인합니다. 컴포넌트 라이브러리에 이상적입니다.
여러 기기에서 E2E 테스트를 병렬로 실행하고, Cloud Device Farm을 사용하며, 테스트를 독립적인 그룹으로 분할하세요. 테스트 최적화: 대기 시간 최소화, 네트워크 요청에 목 사용.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.