모바일 개발에서의 통합 테스트 — 개념, 유형 및 수행 방법

저자: IT Sectr 게시일: 2026-04-06 읽는 시간: 8 분

통합 테스트는 모바일 애플리케이션 컴포넌트—모듈, 서비스, 데이터베이스 및 외부 API—간의 상호작용 과를 검증합니다. 각 컴포넌트를 분리하는 단위 테스트와 달리, 통합 테스트는 집합부에서 에러를 발견합니다: 데이터 포맷 비호환, 파라미터 전송 실패, 서버 응답의 부정한 처리입니다. Martin Fowler, 2018에 따르면, 통합 테스트는 단위 테스트가 높친 치명적 결함의 40%uae4c지 발견하고 릴리스 전에 시스템 안정성에 대한 확신을 제공합니다.

주요 포인트

  • 통합 테스트 — 시스템 컴포넌트간의 상호작용을 검증하는 과정: 데이터베이스, 네트워크 서비스 및 내부 모듈.
  • Big Bang — 모든 컴포넌트를 동시에 연결하여 테스트하는 접근 방식, 작은 프로젝트에 적합.
  • Bottom-Up — 먼저 낮은 레벨의 컴포넌트를 테스트하고, 그 다음에 높은 레벨의 컴포넌트가 점진적으로 추가되는 전략.
  • Top-Down — 상위 인터페이스의 검증부터 시작하여 하위 모듈에 stubs를 사용하는 접균 방식.
  • MockWebServer — Android 테스트에서 HTTP 서버를 에미할레이트하는 라이브러리, 실제 백엔드 없이 네트워크 요청을 검증할 수 있습니다.

통합 테스트란 무엇인가?

통합 테스트는 애플리케이션의 개별 모듈 또는 하위 시스템 간의 상호작용 과를 평가하는 소프트웨어 검증 단계입니다. 단위 테스트가 각 컴포넌트를 분리하여 검증하는 반면, 통합 테스트는 이러한 컴포넌트들을 함께 모아 그들이 함께 어떻게 작동하는지 검증합니다. 일반적인 시나리오는 네트워크 계층과 리포지토리 간의 데이터 전송, ORM을 통한 데이터베이스 쓰기, 그리고 제3자 API 응답 처리를 포함합니다.

모바일 개발의 맥락에서 통합 테스트는 UI 계층, 비즈니스 로직 및 데이터 원천 간의 상호작용을 다룩니다. 예를 들어, 테스트는 "로그인" 버튼을 클릭한 후 애플리케이션이 서버에 요청을 보내고, 토큰을 받아 로컬 저장소에 저장하는지를 확인할 수 있습니다. 이러한 검증은 컴포넌트 체인이 문제없이 작동함을 확인합니다.

World Quality Report 2023에 따르면, 정기적으로 통합 테스트를 적용하는 기업은 단위 테스트에만 의존하는 프로젝트와 비교하여 생산 장애 발생을 35% 감소시킵니다. 이로써 통합 검사는 상용 개발에서 품질 보증 전략의 필수 요소가 됩니다.

모바일 애플리케이션에서 통합 테스트가 중요한 이유

모바일 애플리케이션은 많은 상호 연결된 컴포넌트로 구성됩니다: 네트워크 요청, 로컬 데이터베이스, 퓨시 알림, 시스템 서비스 및 제3자 SDK. 이 각 컴포넌트는 별도로 개발되지만, 실행 시에는 실시간으로 데이터를 주고 받습니다. 통합 테스트는 분리된 모듈 검증으로는 찾을 수 없는 결함을 발견합니다.

통합 테스트가 발견하는 일반적인 문제는 API와 애플리케이션 모델 간의 데이터 타입 불일치, JSON 직렬화 오류, 네트워크 타임아웃의 부정한 처리, Room 또는 Core Data를 통한 동시 데이터베이스 접근 실패 등이 있습니다. 통합 검사 없이는 이러한 결함이 생산에 도달하여 실제 사용자에게만 나타난니다.

Google Testing Blog (2021)의 연구에 따르면, 통합 테스트 단계에서 발견된 결함을 수정하는 비용은 릴리스 이후보다 5배 낮습니다. 이는 초기 단계에서 개발자가 오류의 완전한 맥락을 파악하고 긴급 hotfix 사이클 없이 수정할 수 있기 때문입니다. 통합 테스트를 작성하는 데 시간을 투자하는 것은 유지보수 비용 감소와 사용자 신뢰 향상으로 이어집니다.

통합 테스트 접근 방식

통합 테스트를 조직하는 데는 세 가지 주요 접근 방식이 있습니다: Big Bang, Bottom-Up 그리고 Top-Down. 전략 선택은 프로젝트 규모, 애플리케이션 아키텍처 및 테스트 작성 시점에서의 컴포넌트 가동성에 따라 달라집니다. 각 접근 방식에는 테스트 커버리지를 계획할 때 고려해야 할 장점과 한계가 있습니다.

Big Bang

Big Bang — 시스템의 모든 컴포넌트가 동시에 연결된 후 일반 테스트가 수행되는 접근 방식입니다. 이 방법은 구현하기 간단합니다: stubs를 작성하거나 개별 모듈을 에미할레이트할 필요가 없습니다. 그러나 오류가 발견되면 어떤 컴포넌트가 원인인지 파악하기 어렵습니다. Big Bang은 모듈 수가 5개를 넘지 않는 간단한 아키텍처의 작은 프로젝트에 적합합니다.

Bottom-Up

Bottom-Up — 통합 테스트가 낮은 레벨의 컴포넌트부터 시작되는 전략입니다: 데이터베이스, 네트워크 계층, 시스템 서비스. 각 레벨을 검증한 후 테스트는 점진적으로 높은 레벨의 모듈을 연결합니다 — 리포지토리, Use Case 클래스 및 ViewModel. 주요 장점은 애플리케이션의 기본 계층에서 결함을 조기 발견하여 개발 후기에서 연쇄적 오류 위험을 줄이는 것입니다.

Top-Down

Top-Down — 테스트가 상위 컴포넌트부터 시작되는 접근 방식으로, UI 화면과 네비게이션, 하위 모듈은 stubs 또는 mocks으로 시뮬레이션됩니다. 이를 통해 서버 측이나 데이터베이스가 완전히 구현되기 전에 사용자 시나리오를 검증할 수 있습니다. Top-Down은 백엔드가 아직 실제 통합에 준비되지 않은 경우 클라이언트와 서버 부분의 병렬 개발 시 특히 유용합니다.

통합 테스트 도구

모바일 애플리케이션의 통합 테스트에는 서버 에미레이션 라이브러리, 데이터베이스 프레임워크, 시스템 서비스 검증 도구라는 세 가지 카테고리로 나뉘 전문 도구가 사용됩니다. 구체적인 도구의 선택은 플랫폼 — Android 또는 iOS — 그리고 프로젝트의 기술 스택에 따라 달라집니다.

  • MockWebServer — Android용 Square 라이브러리로, 테스트 환경에서 HTTP 서버를 에미할레이트합니다. 예상 응답 설정, 요청 본문과 헤더 검증, 네트워크 오류 시뮬레이션이 가능합니다.
  • OHHTTPStubs — iOS용 라이브러리로, NSURLProtocol 레벨에서 네트워크 요청을 가로채다 미리 준비된 응답을 반환합니다. 지연 및 연결 오류를 지원합니다.
  • Room Testing — 데이터베이스 테스트를 위한 Android 내장 메커니즘: 인메모리 Room 인스턴스 생성, 읽기 및 쓰기 작업 수행, 마이그레이션 및 트리거 검증.
  • Core Data Testing — iOS 방식으로, 인메모리 Core Data 컨테이너를 생성하여 영구 저장소 없이 쿼리, 엔티티 관계 및 데이터 지속성을 테스트할 수 있습니다.

통합 테스트 코드 예시

Android와 iOS용 통합 테스트의 실제 예를 살펴보겠습니다. Android 플랫폼의 경우 JUnit과 함께 MockWebServer를 사용하고, iOS의 경우 OHHTTPStubs 라이브러리와 XCTest를 사용합니다. 둘 다 API로부터 데이터를 받아 로컬 리포지토리에 저장하는 시나리오를 검증합니다.

Android: MockWebServer로 네트워크 계층 테스트

이 테스트는 에미할레이트된 서버에 대한 Retrofit 요청이 올바른 JSON을 반환하고, 리포지토리가 응답을 도메인 모델로 변환하는지 검증합니다. MockWebServer는 요청을 가로채어 지정된 JSON을 반환하고, 그 후 테스트는 예상된 결과와 실제 결과를 비교합니다.

kotlin
class UserRepositoryTest {
    private val mockServer = MockWebServer()

    @Before
    fun setup() {
        mockServer.start()
    }

    @Test
    fun fetchUser_returnsCorrectData() {
        val json = "{ \`"id\`": 1, \`"name\`": \`"Alice\`" }"
        mockServer.enqueue(MockResponse()
            .setBody(json)
            .setResponseCode(200))

        val repository = UserRepository(
            createRetrofit(mockServer.url("/").toString()))
        val user = repository.fetchUser(1)

        assertEquals(1, user.id)
        assertEquals("Alice", user.name)
    }

    @After
    fun tearDown() {
        mockServer.shutdown()
    }
}

iOS: OHHTTPStubs로 API 요청 테스트

iOS에서는 비슷한 테스트가 URL 요청을 가로채기 위해 OHHTTPStubs를 사용합니다. 이 라이브러리는 URL Loading System의 시스템 프레임워크 레벨에서 서버 응답을 대체하여 URLSession, Alamofire 또는 Moya와 같은 모든 네트워킹 라이브러리를 테스트할 수 있습니다.

swift
import XCTest
import OHHTTPStubs
import OHHTTPStubsSwift

class UserRepositoryTests: XCTestCase {
    func testFetchUser_returnsCorrectData() {
        stub(condition: isPath("/users/1")) { _ in
            return HTTPStubsResponse(
                jsonObject: ["id": 1, "name": "Alice"],
                statusCode: 200,
                headers: nil
            )
        }

        let repository = UserRepository()
        let expectation = expectation(description: "fetch user")

        repository.fetchUser(id: 1) { user in
            XCTAssertEqual(user.id, 1)
            XCTAssertEqual(user.name, "Alice")
            expectation.fulfill()
        }

        waitForExpectations(timeout: 2.0)
    }
}

통합 테스트 최선 실무

효과적인 통합 테스트는 테스트 안정성을 높이고 유지보수 비용을 줄이는 일려의 실무를 따른 필요가 있습니다. 외부 의존성을 분리하세요: 생산 인스턴스 대신 인메모리 데이터베이스를 사용하고 stub 라이브러리를 사용하여 제3자 API를 에미할레이트하세요. 이를 통해 네트워크 가동성 또는 외부 서비스 상태에 의한 비결정적 장애를 제거할 수 있습니다.

테스트 독립성을 유지하세요: 각 통합 테스트는 다른 테스트의 결과에 의존하지 않고 독립적으로 작동해야 합니다. 테스트 환경을 준비하고 청소하려면 JUnit에서 @Before 및 @After 어노테이션을, XCTest에서는 setUp 및 tearDown을 사용하세요. 이를 통해 테스트간 서로 영향을 방지하고 오류 진단을 간소화할 수 있습니다.

국한 사례를 커버하세요: 통합 테스트는 성공 시나리오(happy path)만 그게 아닌 오류 처리 — 타임아웃, HTTP 4xx 및 5xx 코드, 빈 응답, 망가진 JSON — 또한 검증해야 합니다. Google Testing Blog (2022)에 따르면, 생산 장애의 60%가 테스트에서 다루지 않은 국한 사례의 부정 처리와 관련됩니다.

자주 묻는 질문

통합 테스트는 단위 테스트와 어떻게 다른가요?

단위 테스트는 하나의 클래스 또는 함수를 독립적으로 검증하며, 의존성을 stubs로 대체합니다. 통합 테스트는 여러 실제 컴포넌트간의 상호작용을 검증합니다 — 예를 들어, 네트워크 연결과 데이터베이스를 동시에 검증합니다.

통합 테스트 실행에 얼마나 걸리나요?

통합 테스트 실행은 일반적으로 테스트 수와 환경 복잡성에 따라 2분에서 15분 까지 걸립니다. 클 프로젝트의 경우, 머지 전 검증 시간을 줄이기 위해 CI 시스템에서 테스트를 병렬 작업으로 나누는 것이 좋습니다.

어떤 컴포넌트를 통합 테스트로 반드시 커버해야 하나요?

처음으로, 통합 테스트는 네트워크 계층, 데이터베이스 그리고 시스템 서비스에 대해 작성됩니다 — 알림, 카메라, 위치 정보. 백엔드에 대한 API 요청 및 로컬 저장 작업이 가장 높은 ROI를 제공하는데, 이는 이 컴포넌트가 가장 많이 리그레션의 원인이 되기 때문입니다.

단일 화면에 통합 테스트가 필요한가요?

단일 화면의 경우 ViewModel의 단위 테스트와 UI 테스트만으로 매우착합니다. 단일 화면에 대한 통합 테스트는 화면이 여러 데이터 원천과 상호작용하는 경우에만 필요합니다 — 예를 들어, 둘 이상의 API 응답을 결합하거나 네트워크와 로컬 데이터베이스에 동시에 데이터를 쓰는 경우입니다.

통합 테스트는 얼마나 자주 실행해야 하나요?

통합 테스트는 모든 pull request에서 CI 파이프라인과 주요 릴리스 전에 실행해야 합니다. 또한 야간(nightly build)에 통합 테스트의 전체 세트를 실행하여 의존성 또는 테스트 환경의 변경에 관련된 결함을 발견하는 것이 좋습니다.

요약

  • 통합 테스트는 애플리케이션 컴포넌트간의 상호작용을 검증합니다 — 네트워크 계층, 데이터베이스 및 서비스.
  • Big Bang은 작은 프로젝트에 적합하고, Bottom-Up과 Top-Down은 복잡한 아키텍처의 시스템에 적합합니다.
  • MockWebServer와 OHHTTPStubs는 각각 Android와 iOS용 주요 서버 에미레이션 도구입니다.
  • 통합 테스트는 Martin Fowler에 따라 단위 테스트가 높친 결함의 40%까지 발견합니다.
  • 인메모리 데이터베이스와 stubs를 통한 의존성 분리는 테스트 안정성을 높이고 비결정적 장애를 제거합니다.
  • 통합 테스트 단계에서의 수정 비용은 결함이 생산에 도달한 후보다 5배 낮습니다.
  • 완전한 커버리지를 위해 모든 pull request에서 CI 파이프라인과 nightly 실행에 통합 테스트를 포함하세요.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기