4. 앱 액티비티 테스트

액티비티 상태 변경

앱 액티비티 테스트 하는 주된 이유 -> 앱 액티비트를 특정 상태에 배치
특정 요소를 정의하려면 AndroidX 테스트 라이브러리의 일부인 ActivityScenario 인스턴스를 사용

ActivityScenario란?
로컬 단위 테스트 및 기기 내 통합 테스트에서 모두 똑같이 사용할 수 있는 크로스 플랫폼 API.

ActivityScenario기능

1)스레드 안전성을 제공 -> 테스트의 계측 스레드와 테스트 중인 택티비티를 실행하는 스레드 간에 이벤트를 동기화시킴.

2) 테스트중인 액티비티가 제거되거나 생성될 때 어떻게 동작하는지 평가하는 데 특히 적합

액티비티 생성

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEvent() {
            val scenario = launchActivity<MyActivity>()
        }
    }
    

액티비티 생성후 ActivityScenario가 액티비티를 RESUMED 상태로 전환.
RESUMED 상태는 액티비티가 실행 중이며 유저한테 표시됨을 나타냄.
해당 상태에서 Espresso UI 테스트를 사용하여 액티비티의 View 요소와 자유롭게 상호작용할 수 있다.

또한 ActivityScenarioRule을 사용하여

테스트 전 -> ActivityScenario.launch
테스트 해제 -> ActivityScenario.close 자동으로 호출

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @get:Rule var activityScenarioRule = activityScenarioRule<MyActivity>()

        @Test fun testEvent() {
            val scenario = activityScenarioRule.scenario
        }
    }
   

위의 예시는 규칙을 정의하고 규칙에서 시나리오 인스턴스를 얻는 방법을 보여줌.

새로운 상태로 액티비티 변경

액티비티를 CREATED or STARTED 로 변경하려면 moveToState() 호출.
이 작업은 액티비티가 다른 앱이나 시스템 작업에 의해 중단되기 때문에 각각 중지되거나 일시중지된 상황을 시뮬레이션함.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEvent() {
            val scenario = launchActivity<MyActivity>()
            scenario.moveToState(State.CREATED)
        }
    }
    

moveToState() 의 예시.

주의: 테스트 중인 액티비티를 현재 상태로 전환하려고 하면 ActivityScenario는 이 요청을 예외가 아닌 무작동(no-op)으로 처리한다.

현재 액티비티 상태 확인

테스트중인 액티비티의 현재 상태를 확인하려면 ActivityScenario 객체 내의 state 필드 값을 가져와야한다.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEvent() {
            val scenario = launchActivity<MyActivity>()
            scenario.onActivity { activity ->
              startActivity(Intent(activity, MyOtherActivity::class.java))
            }

            val originalActivityState = scenario.state
        }
    }
    

위의 코드에서와 같이 액티비티가 또 다른 액티비티로 리디렉션되거나 자체적으로 완료될 때 테스트 중인 액티비티의 상태를 확인하는 것은 특히 도움이 됨.

액티비티 다시 생성

기기의 리소스가 부족하면 시스템이 활동을 제거할 수 있다.
따라서 유저가 앱으로 돌아올 때 앱이 액티비티를 다시 생성해야할 수 있다.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEvent() {
            val scenario = launchActivity<MyActivity>()
            scenario.recreate()
        }
    }
    

ActivityScenario 클래스는 @NonConfigurationInstance를 사용하여 주석이 지정된 객체 및 액티비티의 저장된 인스턴스 상태를 유지.
이러한 객체는 테스트 중인 액티비티의 새 인스턴스에 로드됨.

액티비티 결과 검색

완료된 액티비티와 연결된 결과 코드 또는 데이터를 얻으려면 ActivityScenario 객체 내의 result 필드 값을 가져와야함.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testResult() {
            val scenario = launchActivity<MyActivity>()
            onView(withId(R.id.finish_button)).perform(click())

            // Activity under test is now finished.

            val resultCode = scenario.result.resultCode
            val resultData = scenario.result.resultData
        }
    }
    

주의: 이는 차단 호출이며 ActivityScenario는 활동에 finish()를 호출하지 않습니다. 테스트 중인 활동이 완료 중이 아니거나 완료되지 않았다면 이 메서드는 시간이 초과되어 런타임 예외가 발생합니다.

액티비티에서 작업 유발

ActivityScenario 내의 모든 메서드는 차단 호출이므로 API를 사용하려면 계측 스레드에서 메서드를 실행해야함.

테스트 중인 액티비티에서 작업을 트리거하려면 Espresson 뷰 매처를 사용하여 뷰의 요소와 상호작용하면 된다.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEvent() {
            val scenario = launchActivity<MyActivity>()
            onView(withId(R.id.refresh)).perform(click())
        }
    }
    

그러나 액티비티 자체에서 메서드를 호출해야 한다면 ActivityAction을 구현하여 안전하게 실행할 수 있다.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEvent() {
            val scenario = launchActivity<MyActivity>()
            scenario.onActivity { activity ->
              activity.handleSwipeToRefresh()
            }
        }
    }
    

좋은 웹페이지 즐겨찾기