반응형

이번 포스팅은 App Fragment Test 에 대하여 알아보도록 하겠습니다.


Fragment는 앱 내에서 재사용 가능한 컨테이너 역할을 하며, 다양한 Activity와 레이아웃 구성에서 동일한 사용자 인터페이스 레이아웃을 표시할 수 있습니다. Fragment는 다양한 용도로 사용되기 때문에 일관적이고 효율적으로 리소스를 사용하는 환경을 제공하는지 검증하는 것이 중요합니다.

Fragment의 외형은 대형 스크린 화면이나 기기에서 가로 모드를 지원하는 Fragment를 포함하여 모든 레이아웃 구성에서 일관적이어야 합니다.

Fragment가 사용자에게 보일 경우에만 Fragment의 뷰 계층 구조를 생성하세요.


Fragment의 상태 변경



이 테스트를 쉽게 설정할 수 있도록 AndroidX는 Fragment를 생성하고 상태를 변경하기 위한 FragmentScenario 라이브러리를 제공합니다.

참고: FragmentScenario 객체가 포함된 테스트 실행을 성공하기 위해 Test 계측 스레드에서 각 API 메서드를 실행하세요. Android 테스트에서 사용한 여러 가지 스레드에 대한 자세한 내용은 테스트의 스레드 이해를 참조하세요.


Test artifact 위치 구성

FragmentScenario를 의도한 대로 사용하려면 다음 소스 코드와 같이 앱의 테스트 APK에서 Fragment test artifact를 app/build.gradle 안에 정의합니다.

dependencies {
   
// ...
   
debugImplementation 'androidx.fragment:fragment-testing:{{ fragment_version }}'
}


Fragment 만들기

FragmentScenario에는 다음 유형의 Fragment를 실행하기 위한 메서드가 포함됩니다.

사용자 인터페이스 포함하는 그래픽 Fragment 입니다. 이 유형의 Fragment를 실행하려면 launchFragmentInContainer()를 호출합니다. FragmentScenario는 Fragment를 Activity의 루트 뷰 컨트롤러에 연결합니다. 그 외의 경우에는 Activity가 포함된 이 작업은 비어 있습니다.

▶ 여러 Activity에 포함된 정보를 단기적으로 실행하거나 저장하는 비 그래픽 Fragment 입니다. 이 유형의 Fragment를 실행하려면 launchFragment()를 호출합니다. FragmentScenario는 이 유형의 조각을 루트 보기가 없는 완전히 빈 활동에 연결합니다.

이런 Fragment 유형 중 하나를 실행한 이후 FragmentScenario는 테스트 중인 Fragment를 RESUMED 상태로 변경합니다. 이 상태는 Fragment가 실행 중이라는 것을 나타냅니다. 그래픽 Fragment를 테스트할 때 사용자에게도 테스트가 보이므로 Espresso UI 테스트를 사용하여 UI 요소에 대한 정보를 평가할 수 있습니다.

다음 소스 코드는 각 유형의 Fragment를 실행하는 방법을 보여줍니다.

<그래픽 Fragment 예시>

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
   
@Test fun testEventFragment() {
       
// The "state" and "factory" arguments are optional.
       
val fragmentArgs = Bundle().apply {
            putInt
("selectedListItem", 0)
       
}
       
val factory = MyFragmentFactory()
       
val scenario = launchFragmentInContainer<MyFragment>(
                fragmentArgs
, factory)
        onView
(withId(R.id.text)).check(matches(withText("Hello World!")))
   
}
}

<비 그래픽 Fragment의 예시>

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
   
@Test fun testEventFragment() {
       
// The "state" and "factory" arguments are optional.
       
val fragmentArgs = Bundle().apply {
            putInt
("numElements", 0)
       
}
       
val factory = MyFragmentFactory()
       
val scenario = launchFragment<MyFragment>(fragmentArgs, factory)
   
}
}


Fragment 다시 생성

기기에 리소스가 부족할 경우 시스템이 Fragment가 포함된 Activity를 소멸할 수 있으며, 이때 사용자가 앱에 돌아왔을 때 앱이 해당 Fragment를 다시 생성해야 합니다. 이 상황을 시뮬레이션하려면 recreate()를 호출하세요.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
   
@Test fun testEventFragment() {
       
val scenario = launchFragmentInContainer<MyFragment>()
       
scenario.recreate()
   
}
}

FragmentScenario 클래스가 테스트 중인 Fragment를 다시 생성하면 Fragment는 다시 생성하기 이전의 수명 주기 상태로 돌아옵니다.


Fragment를 새로운 상태로 변경

앱 UI 테스트에서는 대개 테스트 중인 Fragment를 실행하고 다시 생성하는 것만으로 충분합니다. 그러나 세밀한 유닛 테스트에서는 Fragment가 하나의 수명 주기에서 다른 수명 주기로 넘어갈 때 Fragment의 동작을 평가할 수 있습니다.

Fragment를 다른 수명 주기 상태로 변경하려면 moveToState()를 호출하세요. 이 메서드는 CREATED, STARTED, RESUMED, DESTROYED의 상태를 인수로 지원합니다. 이 작업은 Fragment가 포함된 Activity가 다른 앱이나 시스템 작업에 중단되어 상태를 변경하는 상황을 시뮬레이션합니다.

 참고: Fragment를 DESTROYED 상태로 전환할 경우 해당 Fragment를 다른 상태로 변경할 수 없고 Fragment를 다른 Activity에 연결할 수도 없습니다.

moveToState()의 사용 예시가 다음 소스 코드에서 나타납니다.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
   
@Test fun testEventFragment() {
       
val scenario = launchFragmentInContainer<MyFragment>()
       
scenario.moveToState(State.CREATED)
   
}
}

주의: 테스트 중인 Fragment를 현재의 상태로 전환하려고 할 경우 FragmentScenario는 이 요청을 예외가 아니라 ‑작업 불능으로 취급합니다. 특히, 이 API를 사용하면 Fragment를 DESTROYED 상태로 연속해서 여러 번 전환할 수 있습니다.


Fragment에서 작업 자르기

테스트 중인 Fragment에서 작업을 트리거하려면 Espresso 뷰 매처를 사용하여 뷰에서 요소와 상호작용하세요.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
   
@Test fun testEventFragment() {
       
val scenario = launchFragmentInContainer<MyFragment>()
       
onView(withId(R.id.refresh))
               
.perform(click())

   
}
}

Fragment 자체에서 메서드를 호출해야 할 경우 (예: 옵션 메뉴에서의 선택에 응답) FragmentAction을 구현하면 안전하게 호출할 수 있습니다.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
   
@Test fun testEventFragment() {
       
val scenario = launchFragmentInContainer<MyFragment>()
       
scenario.onFragment(fragment ->
            fragment
.onOptionsItemSelected(clickedItem) {
               
// Update fragment's state based on selected item.
           
}
       
}

   
}
}

참고: 테스트 클래스에서는 onFragment()로 전달한 객체에 대한 참조를 그대로 두지 마세요. 이 참조는 시스템 리소스를 사용하고, 프레임워크가 콜백 메서드로 전달된 Fragment를 다시 생성했기 때문에 참조 자체가 최신이 아닐 수 있습니다.


Reference

1. https://developer.android.com/training/basics/fragments/testing


반응형

'Development > Android' 카테고리의 다른 글

[Android] Intent Filter  (0) 2019.09.10
[Android] Flexable Fragment UI 구축  (0) 2019.09.06
[Android] Fragment의 생성  (0) 2019.09.06
[Android] Fragment의 개요  (0) 2019.09.06
[Android] Button의 배경을 투명하게 하는 방법  (0) 2019.09.05

+ Recent posts