Kotlin에서 Espresso로 UI 테스트 작성

안녕하세요, 여러분! 혹시 안드로이드 앱 개발하면서 UI 테스트 때문에 골머리 앓아본 적 있으신가요? 저도 그랬어요. 버튼 하나 클릭하는 것 테스트하는데 뭐가 이렇게 복잡한지…🤯 그래서 오늘은 KotlinEspresso를 이용해서 쉽고 재미있게 UI 테스트 작성하는 방법을 알려드리려고 해요! Espresso는 안드로이드 UI 테스트를 위한 강력한 도구이고, Kotlin은 간결하고 효율적인 언어잖아요? 이 둘의 조합은 정말 환상적이랍니다. ✨ 이 글에서는 Espresso 기본 설정부터 다양한 UI 상호작용 테스트, 그리고 테스트 실행 및 결과 확인까지 차근차근 설명해드릴 거예요. UI 테스트 작성 시작부터 막막했던 분들, 걱정 마세요! 제가 여러분의 든든한 길잡이가 되어 드릴게요. 😊 자, 이제 Espresso와 Kotlin의 세계로 함께 떠나볼까요?

 

 

Espresso 기본 설정

Espresso로 UI 테스트를 시작하기 전에 꼭 필요한 기본 설정! 마치 맛있는 요리를 하기 전에 재료를 준비하는 것과 같아요. 제대로 된 설정 없이는 Espresso의 강력한 기능을 100% 활용할 수 없답니다. 그러니 지금부터 차근차근 함께 설정해 보아요!

프로젝트 설정 및 의존성 추가

자, 먼저 Android Studio에서 프로젝트를 열어 주세요. build.gradle(:app) 파일을 찾으셨나요? 바로 여기에 Espresso 의존성을 추가해야 해요. 마치 레시피에 필요한 재료를 적어 넣는 것처럼 말이죠! 아래 코드를 dependencies 블록 안에 추가해 주세요. 복사해서 붙여 넣으면 편리해요!

dependencies {
    // ... other dependencies ...

    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    androidTestImplementation("androidx.test.espresso:espresso-contrib:3.5.1") // 이 친구도 필요해요! (RecyclerView, DrawerLayout 등을 테스트할 때!)
    androidTestImplementation("androidx.test:runner:1.5.2") // 테스트 러너!
    androidTestImplementation("androidx.test:rules:1.5.0") // 테스트 규칙!
    // ... more dependencies if needed ...

}

여기서 잠깐! 버전 번호(3.5.1, 1.5.2, 1.5.0)는 항상 최신 버전을 사용하는 것이 좋아요. 마치 요리할 때 신선한 재료를 쓰는 것처럼 말이죠! 최신 버전은 더욱 안정적이고 새로운 기능을 제공할 가능성이 높거든요! Android Developers 사이트나 다른 자료를 참고해서 최신 버전을 확인하고 업데이트해 주세요!

Instrumentation Runner 설정

자, 이제 ‘dependencies’에 Espresso, 테스트 러너, 테스트 규칙을 추가했으니, ‘defaultConfig’ 설정으로 넘어갈게요. 여기서는 instrumentation runner를 설정해야 한답니다. ‘android’ 블록 안에 ‘defaultConfig’ 블록을 찾아 다음 코드를 추가해 주세요.

android {
    // ... other configurations ...

    defaultConfig {
        // ... other default configurations ...

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // 핵심 설정! 잊지 마세요!

        // ... more default configurations if needed ...
    }

    // ... other configurations ...
}

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 이 부분이 정말 중요해요!! 이 설정을 통해 Espresso 테스트가 제대로 실행될 수 있도록 환경을 만들어 준답니다. 마치 요리하기 전에 오븐을 예열하는 것과 같아요! 예열 없이 오븐에 넣으면 맛있는 케이크가 만들어지지 않겠죠?

패키징 옵션 설정

이제 거의 다 왔어요~! 마지막으로, 앱의 build.gradle 파일의 android 블록 안에 다음 코드를 추가해 주세요. 이 부분은 UI 테스트를 위한 중요한 설정들을 담고 있어요!

android {
    // ... other configurations ...
    packagingOptions {
        exclude 'META-INF/AL2.0'
        exclude 'META-INF/LGPL2.1'
        // 만약 다른 충돌이 발생한다면, 여기에 추가해 주세요!
    }

    // ... other configurations ...
}

이 부분은 라이브러리 충돌 문제를 해결하기 위한 설정이에요. 특히, 'META-INF/AL2.0''META-INF/LGPL2.1' 파일은 종종 충돌을 일으키는데, 이 설정을 통해 미리 예방할 수 있답니다. 만약 다른 충돌이 발생한다면, 같은 방식으로 추가해 주시면 돼요!

이제 Espresso 기본 설정이 완료되었어요! 생각보다 간단하죠? 이제 맛있는 UI 테스트를 만들 준비가 모두 끝났어요! 다음 단계에서는 실제로 UI 테스트를 작성하는 방법을 알아볼 거예요. 기대되시죠?! 더 궁금한 점이 있다면 언제든지 질문해 주세요! 다음 소제목에서 만나요!

 

UI 테스트 작성 시작

자, 이제 드디어 본격적으로 Espresso를 이용한 UI 테스트 작성을 시작해 볼까요? Kotlin의 간결함과 Espresso의 강력함이 만나면 어떤 마법같은 테스트 코드가 탄생할지! 정말 기대되네요~?

Espresso 테스트의 구성

먼저, Espresso 테스트는 기본적으로 세 가지 주요 부분으로 구성된다는 것을 알아두면 좋아요. 마치 맛있는 케이크를 만들 때 필요한 핵심 재료처럼 말이죠! 첫 번째는 테스트 대상 뷰를 찾는 onView() 메서드! 두 번째는 뷰와 상호작용하는 perform() 메서드! 마지막 세 번째는 뷰의 상태를 확인하는 check() 메서드입니다! 이 세 가지가 Espresso 테스트의 삼위일체라고 할 수 있겠죠? 이 친구들을 잘 활용하면 웬만한 UI 테스트는 걱정 없답니다!

로그인 테스트 예시

예를 들어, 로그인 버튼을 클릭하고 로그인 성공 메시지가 화면에 표시되는지 확인하는 테스트를 작성한다고 생각해 보세요. 먼저 onView(withId(R.id.login_button))으로 로그인 버튼을 찾아요. 그다음 perform(click())으로 버튼을 꾹! 눌러줍니다. 마지막으로 onView(withText("로그인 성공!")).check(matches(isDisplayed()))로 “로그인 성공!” 메시지가 화면에 잘 보이는지 확인하면 끝! 간단하죠?!

Hamcrest Matcher

Espresso는 Hamcrest 매처(Matcher)를 사용해서 뷰를 찾고, 뷰의 상태를 확인해요. Hamcrest 매처는 굉장히 다양하고 유연해서 복잡한 조건의 뷰도 쉽게 찾을 수 있게 도와준답니다. 예를 들어 withId(), withText(), withHint() 등 여러 가지 매처가 있어요. 이런 다양한 매처들을 활용하면 마치 현미경으로 세밀하게 관찰하듯이 UI 요소들을 꼼꼼하게 테스트할 수 있죠.

실제 코드 예시

자, 그럼 실제 코드를 보면서 좀 더 자세히 알아볼까요? ActivityScenarioRule을 사용하면 테스트할 Activity를 실행하고 관리할 수 있어요. 마치 테스트를 위한 무대를 설치하는 것과 같죠! @RunWith(AndroidJUnit4::class) 어노테이션은 Android JUnit 러너를 사용해서 테스트를 실행하도록 지시해 줍니다. 이 어노테이션이 없으면 테스트가 제대로 실행되지 않으니 꼭 기억해 두세요!

@RunWith(AndroidJUnit4::class)
class LoginActivityTest {

    @get:Rule
    val activityRule = ActivityScenarioRule(LoginActivity::class.java)

    @Test
    fun testLoginSuccess() {
        onView(withId(R.id.username_edittext)).perform(typeText("testuser"))
        onView(withId(R.id.password_edittext)).perform(typeText("password"))
        closeSoftKeyboard() // 소프트 키보드를 닫아 다른 뷰를 가리지 않도록 합니다.
        onView(withId(R.id.login_button)).perform(click())
        onView(withText("로그인 성공!")).check(matches(isDisplayed()))
    }

    // ... 다른 테스트 케이스들 ...
}

closeSoftKeyboard()의 중요성

위 코드에서는 typeText() 메서드를 사용해서 사용자 이름과 비밀번호를 입력하고, click() 메서드로 로그인 버튼을 클릭했어요. 그리고 closeSoftKeyboard() 메서드를 사용해서 소프트 키보드를 닫았는데요, 이 부분이 굉장히 중요해요! 소프트 키보드가 열려 있으면 다른 뷰를 가릴 수 있기 때문에 테스트가 실패할 수도 있거든요. 마치 연극 무대에서 소품이 배우를 가리는 것과 같은 상황이라고 할 수 있죠! 따라서 closeSoftKeyboard()를 호출해서 소프트 키보드를 닫아주는 센스를 발휘해야 한답니다!

ViewActions

Espresso는 ViewActions를 통해 다양한 사용자 상호작용을 시뮬레이션할 수 있어요. click(), typeText(), swipeLeft(), swipeRight(), scrollTo() 등등 정말 많은 액션들이 준비되어 있죠. 마치 마법 주머니에서 원하는 도구를 꺼내 쓰는 것처럼 말이에요! 이러한 다양한 ViewActions를 활용하면 실제 사용자의 행동을 그대로 재현하는 테스트를 만들 수 있답니다.

ViewAssertions

check() 메서드와 함께 사용되는 ViewAssertions는 뷰의 상태를 확인하는 데 사용돼요. matches(isDisplayed()), matches(isEnabled()), matches(withText("특정 텍스트")) 등 다양한 Assertion을 사용할 수 있습니다. ViewAssertions를 잘 활용하면 뷰가 예상대로 동작하는지 꼼꼼하게 검증할 수 있어요! 마치 돋보기로 세밀하게 관찰하는 것처럼 말이죠!

자, 이제 Espresso의 기본적인 사용법을 알아봤으니, 다음에는 좀 더 다양하고 복잡한 UI 상호작용을 테스트하는 방법을 살펴보도록 할게요! 기대해도 좋아요! 더욱 흥미진진한 내용들이 기다리고 있으니까요! 😊

 

다양한 UI 상호작용 테스트

자, 이제 Espresso의 기본 설정을 마쳤으니, 본격적으로 UI 테스트 코드를 작성해 볼까요? 마치 레고 블록을 조립하듯이, 다양한 UI 요소들을 테스트하는 재미를 느껴보실 수 있을 거예요! Espresso는 정말 다양한 상호작용을 테스트할 수 있도록 풍부한 기능들을 제공한답니다. 버튼 클릭부터 텍스트 입력, 스크롤, 심지어는 화면 회전까지! 정말 놀랍지 않나요? 이 부분을 제대로 이해하면 앱의 품질을 한 단계 더 끌어올릴 수 있어요. 그럼, 하나씩 차근차근 살펴보도록 할게요!

버튼 클릭 테스트

먼저, 가장 기본적인 버튼 클릭 테스트부터 시작해 볼까요? onView() 메서드를 사용해서 테스트하려는 뷰를 찾고, perform() 메서드를 이용해서 클릭 액션을 수행할 수 있어요. 예를 들어, ID가 “button_login”인 버튼을 클릭하는 테스트는 다음과 같이 작성할 수 있답니다.

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

참 쉽죠? 이처럼 간단한 코드로 버튼 클릭을 테스트할 수 있어요! 이 코드는 withId() 메서드를 사용해서 특정 ID를 가진 뷰를 찾고, click() 액션을 수행하도록 지시하는 거예요. 만약 버튼을 여러 번 클릭해야 하는 경우라면? click() 대신 doubleClick()이나 longClick()을 사용하면 된답니다. 정말 편리하죠?!

텍스트 입력 테스트

텍스트 입력은 어떻게 테스트할까요? EditText 뷰에 텍스트를 입력하는 테스트는 typeText() 액션을 사용하면 돼요. 예를 들어, ID가 “edit_text_username”인 EditText에 “testuser”라는 텍스트를 입력하는 테스트는 다음과 같이 작성할 수 있어요.

onView(withId(R.id.edit_text_username)).perform(typeText("testuser"))

여기서 중요한 점! 텍스트 입력 후 키보드의 엔터 키를 누르는 동작을 추가하는 것을 잊지 마세요! closeSoftKeyboard() 액션을 추가하면 키보드가 닫히면서 엔터 키를 누른 것과 같은 효과를 낼 수 있답니다. 이 작은 차이가 테스트의 정확도를 높이는 데 큰 도움이 될 수 있어요!

onView(withId(R.id.edit_text_username)).perform(typeText("testuser"), closeSoftKeyboard())

스크롤링 테스트

자, 이제 스크롤링 테스트에 대해 알아볼까요? RecyclerView나 ScrollView와 같은 스크롤 가능한 뷰를 테스트할 때는 scrollTo() 액션을 사용하면 된답니다. 특정 위치로 스크롤하거나, 뷰가 화면에 나타날 때까지 스크롤하는 것도 가능해요! 예를 들어, 특정 텍스트가 포함된 뷰가 보일 때까지 스크롤하는 테스트는 다음과 같이 작성할 수 있어요.

onView(withText("스크롤할 텍스트")).perform(scrollTo())

화면 회전 테스트

화면 회전과 같은 복잡한 상호작용도 Espresso로 테스트할 수 있을까요? 물론이죠! rotateOrientation() 메서드를 사용하면 화면을 가로 또는 세로 모드로 회전시키면서 테스트할 수 있어요. 이 기능을 활용하면 화면 회전 시 UI 요소들이 정상적으로 동작하는지, 데이터가 유지되는지 등을 확인할 수 있답니다. 정말 강력한 기능이죠?!

onView(isRoot()).perform(orientationLandscape())

onView(isRoot()).perform(orientationPortrait())

다양한 뷰 매칭 기능

Espresso는 다양한 뷰 매칭 기능을 제공해요. withId(), withText(), withContentDescription() 등을 사용해서 원하는 뷰를 정확하게 찾을 수 있죠. 또한, allOf() 메서드를 사용하면 여러 조건을 조합해서 더욱 정교하게 뷰를 찾을 수도 있답니다. 마치 돋보기로 원하는 부분을 확대해서 보는 것과 같아요! 예를 들어, 특정 텍스트를 포함하고 특정 ID를 가진 뷰를 찾는 테스트는 다음과 같이 작성할 수 있습니다.

onView(allOf(withId(R.id.text_view), withText("특정 텍스트"))).check(matches(isDisplayed()))

뷰 상태 확인

Espresso는 단순히 UI 상호작용을 테스트하는 것뿐만 아니라, 뷰의 상태를 확인하는 기능도 제공해요. check() 메서드와 matches() 메서드를 함께 사용하면 뷰의 속성, 텍스트, 가시성 등을 검증할 수 있답니다. 예를 들어, 특정 뷰가 화면에 표시되는지 확인하는 테스트는 다음과 같이 작성할 수 있어요.

onView(withId(R.id.text_view)).check(matches(isDisplayed()))

자, 여기까지 Espresso를 이용한 다양한 UI 상호작용 테스트 방법을 살펴보았어요. 어때요? 생각보다 어렵지 않죠? Espresso의 강력한 기능들을 활용하면 앱의 품질을 한층 더 높일 수 있을 거예요! 이제 여러분의 앱에 Espresso를 적용해서 멋진 UI 테스트를 작성해 보세요! 다음에는 테스트 실행 및 결과 확인에 대해 알아보도록 할게요! 기대해 주세요~!

 

테스트 실행 및 결과 확인

후~ 드디어! 힘들었던 테스트 작성 과정을 마쳤다면 이제 떨리는(?) 실행 시간이에요! 마치 마라톤 결승선을 앞둔 기분이랄까요? ^^ Espresso 테스트를 실행하고 결과를 확인하는 방법은 생각보다 간단해요. Android Studio를 사용하고 있다면 몇 번의 클릭만으로도 가능하답니다. 자, 그럼 이제 긴장되는 마음으로 테스트 실행 버튼을 눌러볼까요? 두근두근!

AndroidJUnitRunner

Espresso 테스트는 일반적으로 AndroidJUnitRunner를 통해 실행돼요. 이 AndroidJUnitRunner는 AndroidJUnit4 테스트 프레임워크의 일부로, JUnit4 테스트를 Android 기기나 에뮬레이터에서 실행할 수 있게 해주는 핵심적인 역할을 한답니다. 마치 다리처럼 개발 환경과 테스트 환경을 연결해주는 거죠!

테스트 실행 방법

Android Studio에서 테스트를 실행하는 방법은 여러 가지가 있어요. 개별 테스트를 실행하려면 테스트 클래스를 열고, 실행하고자 하는 테스트 메서드 옆에 있는 녹색 재생 버튼을 클릭하면 돼요. 간단하죠? 전체 테스트 클래스를 실행하려면 클래스 이름 옆에 있는 녹색 재생 버튼을 클릭하면 되고요. 만약 프로젝트의 모든 테스트를 실행하려면, 프로젝트 창에서 ‘app’ 모듈을 마우스 오른쪽 버튼으로 클릭하고 “Run ‘All Tests'”를 선택하면 된답니다. 마치 컴퓨터 게임에서 ‘전체 공격’ 버튼을 누르는 것처럼 말이죠!

테스트 결과 확인

테스트 실행 결과는 Android Studio의 “Run” 창에 표시돼요. 각 테스트의 성공 여부, 실행 시간, 발생한 오류 등을 자세히 볼 수 있죠. 마치 성적표를 받아보는 기분일 거예요. (좋은 결과가 나오길 바라요! 😊) 테스트가 성공하면 녹색 체크 표시가, 실패하면 빨간색 X 표시가 나타나요. 실패한 테스트의 경우, 오류 메시지와 스택 트레이스를 확인하여 문제의 원인을 파악하고 수정해야 해요. 마치 탐정처럼 말이죠! 🕵️‍♀️

Espresso의 상세한 결과 제공

Espresso는 테스트 결과를 매우 상세하게 제공해요. 예를 들어, ViewAssertions를 사용하여 뷰의 상태를 확인한 경우, 예상 값과 실제 값의 차이를 명확하게 보여준답니다. 이를 통해 오류를 빠르게 수정하고 테스트의 정확성을 높일 수 있어요. 마치 현미경으로 세밀하게 관찰하는 것과 같죠! 🔬

테스트 예시

자, 이제 몇 가지 구체적인 예시를 살펴볼까요? 예를 들어, 특정 텍스트 뷰에 “Hello, world!”라는 텍스트가 표시되는지 확인하는 테스트를 작성했다고 가정해 봅시다. 만약 텍스트 뷰에 “Hi, there!”라는 텍스트가 표시된다면, Espresso는 테스트 실패를 보고하고 예상 값(“Hello, world!”)과 실제 값(“Hi, there!”)을 보여줄 거예요. 또 다른 예시로, 버튼을 클릭했을 때 새로운 액티비티가 시작되는지 확인하는 테스트를 생각해 볼 수 있어요. 만약 버튼을 클릭해도 액티비티가 시작되지 않는다면, Espresso는 테스트 실패를 보고하고 그 원인을 분석하는 데 도움이 되는 정보를 제공할 거예요. 정말 똑똑하죠? 😉

테스트 실행 시간

테스트 실행 시간은 앱의 복잡도와 테스트의 규모에 따라 달라져요. 간단한 테스트는 몇 초 만에 완료될 수 있지만, 복잡한 테스트는 몇 분 이상 걸릴 수도 있답니다. 테스트 실행 시간을 단축하기 위해서는 효율적인 테스트 코드를 작성하고, 필요한 경우 테스트를 병렬로 실행하는 방법을 고려해 볼 수 있어요. 마치 여러 개의 CPU 코어를 사용하여 작업 속도를 높이는 것과 같죠! 💻

Espresso의 활용

Espresso는 UI 테스트 자동화를 위한 강력한 도구이지만, 모든 UI 테스트를 Espresso로 작성해야 하는 것은 아니에요. 예를 들어, 앱의 성능 테스트나 접근성 테스트는 다른 도구를 사용하는 것이 더 효율적일 수 있어요. 각 도구의 장단점을 잘 이해하고 상황에 맞는 도구를 선택하는 것이 중요해요. 마치 요리할 때 다양한 조리 도구를 사용하는 것처럼 말이죠! 🍳

 

휴, 드디어 Espresso로 UI 테스트 작성하는 방법에 대한 이야기가 끝났네요! 어때요, 이제 좀 감이 잡히시나요? 처음엔 조금 낯설고 어려워 보였을지 몰라도, 막상 해보면 생각보다 간단하다는 걸 느끼셨을 거예요. Espresso는 정말 강력한 도구라서, 여러분의 앱 품질을 한 단계 높여줄 비밀 병기 같은 존재랍니다. 이제 여러분의 앱은 Espresso 덕분에 버그 걱정 없이 훨씬 안정적이고 멋진 앱이 될 거예요. 앞으로 앱 개발하면서 Espresso와 함께 즐거운 코딩 시간 보내시길 바라요! 궁금한 점이 있다면 언제든지 질문해주세요. 함께 배우고 성장하는 즐거움을 나누면 좋겠어요!

 

Leave a Comment