Espresso — 개념, 작동 원리 및 사용 방법

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

Espresso는 Google 팀이 개발하고 AndroidX Test에 포함된 Android 애플리케이션용 자동화 UI 테스트 프레임워크입니다. 격리된 구성 요소를 확인하는 계측 테스트와 달리 Espresso는 실제 UI와 상호 작용합니다: 버튼을 클릭하고, 텍스트를 입력하고, 요소 표시를 확인합니다. Google Android Developers에 따르면 Espresso는 UI 스레드와 자동 동기화를 제공하여 수동 Thread.sleep()이 필요하지 않습니다.

핵심 요점

  • Espresso — 자동 스레드 동기화를 갖춘 Android UI 테스트 프레임워크.
  • ViewMatcher — ID, 텍스트 또는 상위 계층 구조로 화면에서 View 요소를 찾습니다.
  • ViewAction — 요소에 대한 작업 수행: 클릭, 텍스트 입력, 스와이프.
  • ViewAssertion — 요소 상태 확인: 표시됨, 텍스트 포함, 활성화됨.
  • Idling Resource — UI 확인 전에 비동기 작업 완료를 기다리는 메커니즘.

Espresso란?

Espresso는 Android용 자동화 UI 테스트를 작성하기 위한 라이브러리로, Google AndroidX Test의 일부입니다. 화면에서 View 요소를 찾고, 요소에 대한 작업(클릭, 입력, 스와이프)을 수행하며, 상태(표시됨, 텍스트 포함, 활성화됨)를 확인하는 API를 제공합니다.

Espresso의 주요 기능은 애플리케이션의 메인 스레드와 자동 동기화입니다. 프레임워크는 다음 확인을 실행하기 전에 모든 비동기 작업(coroutine, AsyncTask, Handler)이 완료될 때까지 기다립니다. 이로 인해 경합 상태로 인한 불안정한 테스트가 제거되고 UI 테스트가 안정적이고 신뢰할 수 있게 됩니다 — 어떤 테스트도 Thread.sleep() 또는 대기 루프를 포함하지 않습니다.

Espresso는 세 발 달린 개 원칙을 따릅니다 — 테스트는 세 단계로 구성됩니다: 요소 찾기(ViewMatcher), 작업 수행(ViewAction), 결과 확인(ViewAssertion). 세 단계 모두 onView().perform().check() 호출 체인으로 작성됩니다. 이 개념은 테스트를 예측 가능하고 읽기 쉽게 만듭니다 — 각 테스트는 무엇을 찾고, 무엇을 하고, 무엇을 확인하는지 명시적으로 설명합니다.

Espresso 작동 방식

아키텍처 Espresso는 세 가지 구성 요소를 기반으로 합니다: Espresso(진입점 — 정적 메서드 onView 및 onData), ViewMatchers(요소 검색), ViewActions(작업) 및 ViewAssertions(확인). 내부적으로 프레임워크는 UI 스레드와의 동기화를 위해 Idling Resource를 사용합니다.

기본 Espresso 테스트

가장 간단한 테스트는 ID로 버튼을 찾고, 클릭을 수행하고, “완료” 텍스트가 나타나는지 확인합니다. 테스트 관점에서 모든 작업은 동기식입니다 — Espresso는 테스트가 계속되기 전에 UI 스레드가 이벤트 처리를 완료했음을 보장합니다. 이는 내장된 대기 메커니즘을 통해 달성됩니다: onView는 UI가 유휴 상태가 될 때까지 테스트 실행을 차단합니다.

kotlin
@Test
fun buttonClick_showsSuccessText() {
    // ID로 버튼 찾아 클릭
    onView(withId(R.id.button_submit))
        .perform(click())

    // “완료” 텍스트가 표시되는지 확인
    onView(withText("완료"))
        .check(matches(isDisplayed()))
}

ActivityScenario 규칙

Espresso 테스트를 시작하려면 ActivityScenario(AndroidX Test)가 사용되며, 특정 상태(실행 중, 일시 중지됨, 소멸됨)에서 Activity를 생성합니다. ActivityScenario를 사용하면 순수 UI 테스트 외에도 Activity 수명 주기를 테스트할 수 있습니다. 예를 들어 화면 회전(Activity 재생성) 시 데이터가 보존되고 소멸 후 복원되는지 확인할 수 있습니다.

ViewMatchersEspresso.onView 클래스의 메서드 집합으로, 리소스 ID(R.id), 텍스트, 힌트, 상위 요소 및 계층 구조 등 다양한 기준으로 화면에서 Views를 찾을 수 있습니다. 하나의 Matcher로 고유한 결과가 나오지 않으면 allOf()를 사용하여 Matcher를 결합할 수 있습니다.

Matcher목적
withId(R.id.name)리소스 ID로 검색
withText(“텍스트”)표시된 텍스트로 검색
withHint(“힌트”)EditText의 힌트 속성으로 검색
isDisplayed()요소가 화면에 표시되는지 확인
hasSibling(matcher)형제 요소로 검색
allOf(m1, m2)여러 Matcher 결합

Matcher 결합

화면에 여러 개의 동일한 요소가 있는 경우(예: 다른 텍스트를 가진 두 개의 TextView), allOf를 사용하여 Matcher를 결합하는 것이 편리합니다: onView(allOf(withId(R.id.title), withText(“안녕하세요”))). 이렇게 하면 단일 요소 선택이 보장됩니다. 역 연산자 — not() — 는 요소를 검색에서 제외하고, hasSibling()은 알려진 요소 옆에 있는 요소를 찾습니다.

ViewActions: UI와 상호 작용

ViewActions는 Espresso가 찾은 View에서 수행하는 작업입니다: click(), typeText(), clearText(), scrollTo(), swipeLeft() 등. 작업은 perform() 메서드에 전달되며, 여러 작업을 순차적으로 허용할 수 있습니다.

작업 체이닝

perform() 메서드는 vararg ViewAction을 허용하여 하나의 요소에 대한 일련의 작업을 실행할 수 있습니다: 필드 지우기, 새 텍스트 입력, 키보드 닫기, 버튼 클릭. 모든 작업은 나열된 순서대로 실행되며, Espresso는 이전 작업이 완료된 후 다음 작업이 시작됨을 보장합니다.

kotlin
// EditText에 텍스트 입력하고 버튼 클릭
onView(withId(R.id.edit_email))
    .perform(
        clearText(),
        typeText("user@example.com"),
        closeSoftKeyboard()
    )

onView(withId(R.id.button_login))
    .perform(click())

onData를 통한 확인

AdapterView(ListView, RecyclerView) 내부의 요소에는 onView 대신 onData() 메서드가 사용됩니다. Views 대신 어댑터 데이터로 작업합니다 — 모델 콘텐츠로 요소를 찾고 추가 작업을 위해 해당 View를 반환합니다. onData는 모델 데이터 필드로 요소를 찾기 위해 hamcrest Matcher를 사용합니다.

ViewAssertions: 상태 확인

ViewAssertions는 View가 특정 상태에 있는지 확인합니다. 기본 메서드 — matches(matcher) — 는 요소가 지정된 Matcher와 일치하는지 확인합니다. 또한 Espresso는 doesNotExist()(요소 없음) 및 selectedDescendantsMatch()(중첩 요소 확인)를 제공합니다.

일반적인 확인

UI 테스트에서 가장 빈번한 확인: 요소가 표시됨(isDisplayed), 요소에 특정 텍스트가 포함됨(withText), 요소가 활성화됨(isEnabled), 요소가 선택되지 않음(isNotChecked). 각 확인은 실패 시 상세한 예외를 throw합니다 — 화면의 View 계층 구조를 포함합니다. 이는 디버깅을 단순화합니다: 오류 메시지는 확인 당시 화면에 실제로 어떤 요소가 있었는지 보여줍니다.

사용자 정의 ViewAssertions

표준 확인이 충분하지 않은 경우 ViewAssertion 인터페이스를 통해 사용자 정의 확인을 만들 수 있습니다. 사용자 정의 assertion은 View를 받아 프로그래밍 방식으로 상태를 확인할 수 있습니다 — 예: 텍스트 색상, 패딩 또는 표준 Matcher를 통해 노출되지 않은 사용자 정의 구성 요소의 상태.

kotlin
// 확인: TextView가 표시되고 텍스트 포함
onView(withId(R.id.text_welcome))
    .check(matches(isDisplayed()))
    .check(matches(withText("환영합니다")))

// 확인: 요소가 표시되지 않음
onView(withId(R.id.progress_bar))
    .check(doesNotExist())

비동기 작업을 위한 Idling Resources

Idling Resource는 비동기 작업과 테스트를 동기화하기 위한 Espresso의 메커니즘입니다. 기본적으로 Espresso는 Handler, AsyncTask 및 coroutine(coroutinesIdlingResource를 통해)을 기다립니다. 애플리케이션이 사용자 정의 스레드 또는 콜백 서비스를 통해 백그라운드 작업을 수행하는 경우 사용자 정의 Idling Resource를 등록해야 합니다.

Coroutine을 사용한 예제

AndroidX Test 1.4.0부터 Espresso는 CoroutinesIdlingResource를 통해 coroutine을 지원합니다. 테스트는 UI 확인을 수행하기 전에 시작된 모든 coroutine이 완료될 때까지 자동으로 기다립니다. 더 복잡한 시나리오의 경우 CountingIdlingResource가 사용됩니다 — 작업 시작 시 증가하고 완료 시 감소하는 카운터입니다.

kotlin
// OkHttp용 IdlingResource 등록
class OkHttpIdlingResource(
    private val client: OkHttpClient
) : IdlingResource {

    private var isIdle = true
    private var watcher: IdlingResource.ResourceCallback? = null

    override fun getName() = "OkHttp"

    override fun isIdleNow() = isIdle

    override fun registerIdleTransitionCallback(
        callback: IdlingResource.ResourceCallback
    ) {
        watcher = callback
    }
}

Android 프로젝트에서 Espresso 설정

연결 Android 프로젝트에 Espresso를 추가하려면 모듈 수준의 build.gradle에 종속성을 추가합니다. Espresso는 AndroidX Test의 일부이므로 Espresso 코어, 확장 기능 및 JUnit 통합에 대한 종속성을 지정하는 것으로 충분합니다. 테스트는 src/androidTest 디렉토리에 배치되며 AndroidJUnitRunner를 통해 물리적 장치 또는 에뮬레이터에서 실행됩니다.

Gradle 구성

최소 종속성 세트에는 espresso-core(코어), espresso-contrib(RecyclerView, Drawer, Picker용 추가 Matcher) 및 runner(AndroidX 테스트 러너)가 포함됩니다. 모든 테스트는 Android Test Orchestrator를 통해 에뮬레이터 또는 물리적 장치에서 실행됩니다.

kotlin
// build.gradle.kts (androidTest 종속성)
android {
    defaultConfig {
        testInstrumentationRunner =
            "androidx.test.runner.AndroidJUnitRunner"
    }
}

dependencies {
    androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
    androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.1")
    androidTestImplementation("androidx.test:runner:1.6.1")
    androidTestImplementation("androidx.test:rules:1.6.1")
}

CI에서 테스트 실행

Espresso 테스트는 Google Android Test Orchestrator를 통해 실행할 수 있으며, 각 테스트를 별도 프로세스로 격리하고 실행 간 상태를 정리합니다. 이전 테스트의 잔여 데이터로 인한 불안정한 테스트를 제거하고 CI 서버에서 안정성을 향상시킵니다. 병렬 실행을 위해 sharding이 사용됩니다 — 여러 에뮬레이터 간 테스트 분산.

자주 묻는 질문

Espresso와 UI Automator의 차이점은?

Espresso는 애플리케이션 프로세스 내에서 작동하며 UI 스레드와 자동 동기화를 사용합니다. UI Automator는 시스템 수준에서 작동하며 다른 애플리케이션과 상호 작용할 수 있지만 수동 대기 관리가 필요합니다.

Espresso가 “세 발 달린 개” 프레임워크라고 불리는 이유는?

Google 프레젠테이션의 은유입니다: Espresso 테스트는 세 개의 기둥 — ViewMatcher(찾기), ViewAction(실행) 및 ViewAssertion(확인) — 위에 서 있습니다. 하나라도 제거하면 세 발 달린 개처럼 테스트가 불안정해집니다.

Espresso로 RecyclerView를 테스트하는 방법은?

RecyclerView의 경우 espresso-contrib 라이브러리와 onView(withId(R.id.recycler)).perform(actionOnItemAtPosition(0, click())) 같은 메서드가 사용됩니다. 대안은 AdapterView용 onData() 또는 RecyclerView 내부의 텍스트로 요소를 찾는 사용자 정의 ViewAction입니다. 또한 espresso-contrib의 RecyclerViewActions를 사용하여 요소로 스크롤하고 작업을 수행할 수 있습니다.

플래키 테스트란 무엇이며 Espresso는 어떻게 대처하나요?

플래키 테스트는 코드 변경 없이 경합 상태나 비동기성으로 인해 때때로 실패하는 테스트입니다. Espresso는 Idling Resource를 사용하여 이 문제를 해결합니다 — 확인을 수행하기 전에 모든 백그라운드 작업이 완료될 때까지 기다립니다.

Espresso를 스크린샷 테스트에 사용할 수 있나요?

Espresso 자체는 스크린샷 테스트용으로 설계되지 않았지만 Shot 또는 Paparazzi 같은 라이브러리와 결합할 수 있습니다. Espresso가 UI를 원하는 상태로 준비하고 비교 라이브러리가 스크린샷을 찍어 참조 이미지와 비교합니다. 이 접근 방식을 시각적 회귀 테스트라고 하며 인터페이스의 예기치 않은 변경 사항을 찾는 데 도움이 됩니다.

요약

  • Espresso — 자동 동기화를 갖춘 Google의 Android UI 테스트 프레임워크.
  • ViewMatchers — ID, 텍스트, 계층 구조 및 조합으로 요소를 찾는 API.
  • ViewActions — UI 상호 작용을 위한 click, typeText, scrollTo, swipe.
  • ViewAssertions — 요소 상태 확인을 위한 matches, doesNotExist.
  • Idling Resource — 비동기 작업 및 coroutine과 테스트 동기화.
  • 세 단계 — onView().perform().check() = 찾기, 실행, 확인.
  • AndroidX Test — 에뮬레이터 또는 장치에서 계측 테스트를 실행하기 위한 라이브러리.

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

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

프로젝트 논의

더 읽어보기