Espresso 테스트 레코더 배포

16171 단어 AndroidUITestEspresso

입문


Android Studio에 탑재된 UI 테스트 로깅 도구인 Espresso Test Recorder를 사용해 보았습니다.
Espresso Test Recorder는 응용 프로그램의 동작을 기록하여 자동으로 Espresso의 테스트 코드로 변환하는 편리한 도구입니다.
Espresso의 API 지식이 없어도 테스트를 직관적으로 제작할 수 있습니다.
아래와 같이 클릭하면 문자가 쉽게 변하는 예시 코드로 실제 확인합니다.

실행

  • Android Studio에서 테스트할 항목을 엽니다
  • 테스트 응용 프로그램 동작 단말기나 시뮬레이터를 준비합니다
  • 물론 상술한 두 가지 준비가 필요하다.
    Android Studio에서 터미널을 인식한 상태에서 Run->Record Espresso Test를 선택한 후 기록을 시작합니다.

    프로그램이 터미널에서 시작되고 Android Studio에 Record Your Test라고 적힌 대화상자가 표시되어 기록될 수 있는 상태가 됩니다.

    레코드


    기록이 시작되면 실제 테스트하고 싶은 순서에 따라 프로그램을 조작합니다.
    매번 한 번 조작하면 사용자 테스트 대화상자에 기록된 조작 내용을 기록합니다.
    기록 시 응답 속도가 느리기 때문에 대화 상자에 작업 내용이 반영될 때까지 기다렸다가 다음 작업을 진행하십시오.
    잘못된 조작도 그대로 기록되기 때문에 주의해야 하지만 이후에는 수동으로 코드를 수정하면 되기 때문에 너무 신경 쓸 필요가 없다.

    단언


    단언을 기록하려면 Record Your Test 대화 상자의 오른쪽 아래에 있는 도우미 추가 버튼을 누릅니다.
    버튼을 누르고 잠시 기다리면 오른쪽 부분에 테스트 대상 프로그램의 화면이 표시됩니다.
    다음 조작을 통해 단언을 기록합니다.
  • 캡처에서 검증하고 싶은 부위를 누르세요
  • 검증 대상View가 빨간색 테두리로 둘러싸여 있기 때문에 대상이 정확한지 확인합니다
  • 대화상자 왼쪽 아래에 있는 편집 assertion 상자에 단언을 설정합니다
  • 확인 대화 상자의 왼쪽 위에 검증 순서가 기록되어 있습니다

  • Another 저장 및 추가 버튼
    단언을 기록하고 다른 단언을 계속 기록합니다
    도움말 저장 버튼
    단언을 기록하고 비헤이비어 레코드로 돌아가기

    단언 유형


    text is


    편집 assertion에서 지정한 보기 텍스트 문자열과 일치하는지 확인하기

    exists


    편집 assertion에서 지정한 보기가 존재하는지 확인하기

    does not exist


    편집 assertion에서 지정한 보기가 존재하지 않는지 확인하기

    테스트 저장


    방금 대화 상자의 오른쪽 아래에 있는 OK 를 누르면 테스트가 자동으로 생성됩니다.
    테스트 클래스와 언어를 물어볼 수 있으니 입력하고 저장하세요.

    생성된 테스트 코드


    버튼을 클릭하면 지정된 문자열이 표시되는지 테스트가 자동으로 생성됩니다.
    MainActivityTest.kt
    package net.storehouse.nono.espressotestrecordersample
    
    
    import android.support.test.espresso.Espresso.onView
    import android.support.test.espresso.action.ViewActions.click
    import android.support.test.espresso.assertion.ViewAssertions.matches
    import android.support.test.espresso.matcher.ViewMatchers.*
    import android.support.test.filters.LargeTest
    import android.support.test.rule.ActivityTestRule
    import android.support.test.runner.AndroidJUnit4
    import android.view.View
    import android.view.ViewGroup
    import org.hamcrest.Description
    import org.hamcrest.Matcher
    import org.hamcrest.Matchers.allOf
    import org.hamcrest.TypeSafeMatcher
    import org.junit.Rule
    import org.junit.Test
    import org.junit.runner.RunWith
    
    @LargeTest
    @RunWith(AndroidJUnit4::class)
    class MainActivityTest {
    
        @Rule
        @JvmField
        var mActivityTestRule = ActivityTestRule(MainActivity::class.java)
    
        @Test
        fun mainActivityTest() {
            val appCompatButton = onView(
                allOf(
                    withId(R.id.button), withText("クリックする?"),
                    childAtPosition(
                        childAtPosition(
                            withId(android.R.id.content),
                            0
                        ),
                        2
                    ),
                    isDisplayed()
                )
            )
            appCompatButton.perform(click())
    
            val textView = onView(
                allOf(
                    withId(R.id.main_text), withText("ボタンがクリックされました!"),
                    childAtPosition(
                        childAtPosition(
                            withId(android.R.id.content),
                            0
                        ),
                        0
                    ),
                    isDisplayed()
                )
            )
            textView.check(matches(withText("ボタンがクリックされました!")))
    
            val appCompatButton2 = onView(
                allOf(
                    withId(R.id.button), withText("元に戻す"),
                    childAtPosition(
                        childAtPosition(
                            withId(android.R.id.content),
                            0
                        ),
                        2
                    ),
                    isDisplayed()
                )
            )
            appCompatButton2.perform(click())
    
            val textView2 = onView(
                allOf(
                    withId(R.id.main_text), withText("ボタンをクリックしてね"),
                    childAtPosition(
                        childAtPosition(
                            withId(android.R.id.content),
                            0
                        ),
                        0
                    ),
                    isDisplayed()
                )
            )
            textView2.check(matches(withText("ボタンをクリックしてね")))
    
            val textView3 = onView(
                allOf(
                    withId(R.id.main_text2), withText("押すとこのテキストは消えるよ"),
                    childAtPosition(
                        childAtPosition(
                            withId(android.R.id.content),
                            0
                        ),
                        1
                    ),
                    isDisplayed()
                )
            )
            textView3.check(matches(withText("押すとこのテキストは消えるよ")))
        }
    
        private fun childAtPosition(
            parentMatcher: Matcher<View>, position: Int
        ): Matcher<View> {
    
            return object : TypeSafeMatcher<View>() {
                override fun describeTo(description: Description) {
                    description.appendText("Child at position $position in parent ")
                    parentMatcher.describeTo(description)
                }
    
                public override fun matchesSafely(view: View): Boolean {
                    val parent = view.parent
                    return parent is ViewGroup && parentMatcher.matches(parent)
                            && view == parent.getChildAt(position)
                }
            }
        }
    }
    
    

    테스트 결과


    시험도 통과할 거야.

    신경 쓰이는 곳

  • does not exist에서view가 존재하지 않는다는 단언을 확인할 때 화면 스냅샷에 존재하지 않는View를 선택할 수 없기 때문에 최종적으로 수동으로 만들어야 합니다
  • 불필요한 작업을 저장하고 매번 삭제하는 것은 매우 번거롭다
  • 불편한 점은 있지만 간단한 테스트나 간단한 프레임워크로 만들 수 있습니다.

    좋은 웹페이지 즐겨찾기