관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[코틀린] 안드로이드 UI Unit Test with Espresso 본문

안드로이드/Unit Test

[코틀린] 안드로이드 UI Unit Test with Espresso

막무가내막내 2020. 9. 4. 22:30
728x90

 

안녕하세요. 안드로이드 UI 테스트시 이용되는 Espresso 에 대해 간략히 정리해보는 포스팅을 갖도록 하겠습니다. ㅎㅎ

 

UI 테스트는 왜 필요할까요? 문서에는 다음과 같이 정리되어 있습니다.

단일 앱 내에서 사용자 상호작용을 테스트하면 사용자가 앱과 상호작용할 때 예상치 못한 결과가 발생하거나 불만족스러운 경험을 하지 않도록 할 수 있습니다. 앱의 사용자 인터페이스(UI)가 올바르게 작동하는지 확인해야 한다면 UI 테스트를 만드는 습관을 들여야 합니다.

AndroidX 테스트에서 제공하는 Espresso 테스트 프레임워크는 단일 타겟 앱 내에서 사용자 상호작용을 시뮬레이션하는 UI 테스트를 작성하기 위한 API를 제공합니다. Android 2.3.3(API 수준 10) 이상을 실행하는 기기에서 Espresso 테스트를 실행할 수 있습니다. Espresso 사용의 주요 이점은 테스트 중인 앱의 UI와 테스트 작업을 자동으로 동기화한다는 것입니다. Espresso는 기본 스레드가 유휴 상태인 시점을 감지하므로 적절한 시간에 테스트 명령어를 실행하여 테스트 신뢰성을 향상할 수 있습니다. 이 기능을 사용하면 Thread.sleep()과 같은 타이밍 해결 방법을 테스트 코드에 추가하지 않아도 됩니다.

Espresso 테스트 프레임워크는 계측 기반 API이며 AndroidJUnitRunner 테스트 실행기와 호환됩니다.

 

이러한 이유로 UI 테스트가 필요하고 이 테스트를 위해 안드로이드에서는 Espresso 를 사용합니다.

그럼 실제 적용해본 간단한 예제 코드를 통해 알아보도록 하겠습니다.

실습예제의 내용은 다음과 같은 이메일 회원가입 창이 있는데 이메일 주소오 비밀번호만 입력하고 비밀번호 확인은 입력하지 않은채 회원가입하고 시작 버튼을 눌렀을 때 떠야할 에러메시지가 나오는지 테스트하는 예제입니다.

 

 

 

 

 

 

1. 먼저 앱 수준의 Build.gradle에 Unit Test 디펜던시를 추가합니다. Espresso 외에 Junit4, Mockito 등 제가 사용하는 디펜던시 모음 입니다.

 // test
    testImplementation 'junit:junit:4.12'
    testImplementation 'org.mockito:mockito-core:3.3.1'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    testImplementation 'org.mockito:mockito-inline:3.2.4'
    androidTestImplementation 'org.mockito:mockito-android:3.2.4'
    androidTestImplementation 'com.android.support.test:rules:1.0.2'
    debugImplementation 'androidx.fragment:fragment-testing:1.2.5'
    testImplementation 'org.mockito:mockito-core:3.3.1'
    androidTestImplementation 'androidx.arch.core:core-testing:2.1.0'

 

 

2. ViewModel 라이브데이터를 옵저빙하는 액티비티 단의 코드인데 각각의 상황에 맞은 에러메시지를 띄워줍니다.

여기서 할거는 isPasswordConfirmEmpty 에러메시지를 확인하는 테스트입니다.

private fun initViewModelCallback() {
        with(viewModel) {
            isEmailEmpty.observe(this@EmailSignUpActivity, Observer {
                binding.etEmail.error = getString(R.string.enter_email_text)
            })
            isPwEmpty.observe(this@EmailSignUpActivity, Observer {
                binding.etPw.error = getString(R.string.enter_password_text)
            })
            isPwConfirmEmpty.observe(this@EmailSignUpActivity, Observer {
                binding.etPwConfirm.error = getString(R.string.enter_password_confirm_text)
            })
            pwNotMatch.observe(this@EmailSignUpActivity, Observer {
                showToast(getString(R.string.password_confirm_not_same_text))
            })
            signUp.observe(this@EmailSignUpActivity, Observer {
                signUp(email.value!!, pw.value!!)
            })
        }
    }

 

 

3. 테스트 클래스를 만들어줍니다. 안드로이드에는 androidTest 와 그냥 test 가 있는데 androidTest 에 만들어주도록 합니다. 

 

 

 

[+ androidTest 와 test 의 차이점입니다.]

 

 

 

 

4. Espresso 도 여러가지 테스트 함수를 제공합니다. 해당 함수들은 문서나 www.vogella.com/tutorials/AndroidTestingEspresso/article.html 다음 사이트에서 찾아보시면 됩니다. (간단하므로 그냥 코드만 보셔도 이해하실거라 믿습니다.) 저는 처음 말한 패스워드 확인 입력이 비었을 경우의 에러메세지를 확인하는 테스트를 진행해보겠습니다. 참고로 ViewActions.closeSoftKeyboard() 는 키보드 관련 문제로 Espresso Unit Test 가 멈추는 경우가 있는데 그걸 해결하기 위해 추가했습니다.

package com.mtjin.nomoneytrip.views.email_signup

import android.content.Context
import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import androidx.test.runner.AndroidJUnit4
import com.mtjin.nomoneytrip.R
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class EmailSignUpActivityTest {

    @get:Rule
    val activityRule = ActivityTestRule(EmailSignUpActivity::class.java)
    private val appContext: Context = InstrumentationRegistry.getInstrumentation().targetContext

    @Before
    fun setUp() {
    }

    @After
    fun tearDown() {
    }

    @Test
    fun password_confirm_edittext_show_error_message_if_it_empty() {
        Espresso.onView(withId(R.id.et_email))
            .perform(ViewActions.typeText("JackJackE@github.com"), ViewActions.closeSoftKeyboard())
        Espresso.onView(withId(R.id.et_pw))
            .perform(ViewActions.typeText("111111"), ViewActions.closeSoftKeyboard())
        Espresso.onView(withId(R.id.iv_signup)).perform(ViewActions.click())
        Espresso.onView(withId(R.id.et_pw_confirm))
            .check(ViewAssertions.matches(ViewMatchers.hasErrorText(appContext.getString(R.string.enter_password_confirm_text))))
    }
}

 

 

[실행 결과]

 

 

 

 

 

 

이상 Espresso 유닛테스트와 간단한 예제를 함께 살펴보았습니다. 

댓글과 공감은 큰 힘이 됩니다. 감사합니다 !!

 

[참고]

developer.android.com/training/testing/espresso?hl=ko

 

Espresso  |  Android 개발자  |  Android Developers

Espresso를 사용하면 간결하고 아름답고 신뢰할 수 있는 Android UI 테스트를 작성할 수 있습니다. 다음 코드 스니펫은 Espresso 테스트의 예를 보여줍니다. Kotlin @Test fun greeterSaysHello() { onView(withId(R.id.na

developer.android.com

developer.android.com/training/testing/ui-testing/espresso-testing?hl=ko

 

단일 앱의 UI 테스트  |  Android 개발자  |  Android Developers

단일 앱 내에서 사용자 상호작용을 테스트하면 사용자가 앱과 상호작용할 때 예상치 못한 결과가 발생하거나 불만족스러운 경험을 하지 않도록 할 수 있습니다. 앱의 사용자 인터페이스(UI)가 ��

developer.android.com

github.com/android/testing-samples

 

android/testing-samples

A collection of samples demonstrating different frameworks and techniques for automated testing - android/testing-samples

github.com

 

728x90
Comments