앱 프래그먼트 테스트

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

프래그먼트는 앱에서 재사용할 수 있는 컨테이너 역할을 하므로 프래그먼트를 사용하면 다양한 활동과 레이아웃 구성에서 동일한 사용자 인터페이스 레이아웃을 제공할 수 있습니다. 이렇게 용도가 다양한 프래그먼트를 고려할 때 일관되고 리소스 효율적인 환경을 제공하는지 검증하는 것이 중요합니다.

  • 프래그먼트의 모양은 대형 화면 크기나 가로 모드 기기 방향을 지원하는 레이아웃 구성을 포함하여 레이아웃 구성 전체에서 일관성이 있어야 합니다.
  • 프래그먼트가 사용자에게 표시되지 않는 한 프래그먼트의 뷰 계층 구조를 만들지 마세요.

이 문서에서는 각 프래그먼트의 동작을 평가하는 테스트에 프레임워크 제공 API를 포함하는 방법을 설명합니다.

프래그먼트 상태 변경

이러한 테스트를 실행하는 조건을 설정하는 데 도움이 되도록 AndroidX는 프래그먼트를 만들고 그 상태를 변경하기 위한 FragmentScenario 라이브러리를 제공합니다.

종속 항목 선언

FragmentScenario를 의도한 대로 사용하려면 다음 코드 스니펫과 같이 앱의 테스트 APK에서 프래그먼트 테스트 아티팩트를 정의합니다.

app/build.gradle

    dependencies {
        def fragment_version = "1.2.4"
        // ...
        debugImplementation 'androidx.fragment:fragment-testing:$fragment_version'
    }
    

이 라이브러리의 현재 버전을 보려면 버전 페이지에서 프래그먼트에 관한 정보를 확인하세요.

프래그먼트 만들기

FragmentScenario에는 다음 유형의 프래그먼트를 실행하는 메서드가 포함되어 있습니다.

이 메서드는 다음 유형의 프래그먼트도 지원합니다.

  • 그래픽 프래그먼트. 사용자 인터페이스가 포함되어 있습니다. 이 유형의 프래그먼트를 실행하려면 launchFragmentInContainer()를 호출합니다. FragmentScenario는 프래그먼트를 활동의 루트 뷰 컨트롤러에 연결합니다. 이러한 활동은 그 외의 경우에는 비어 있습니다.
  • 그래픽이 아닌 프래그먼트(헤드리스 프래그먼트라고도 함). 여러 활동에 포함된 정보의 단기 처리를 저장하거나 실행합니다. 이 유형의 프래그먼트를 실행하려면 launchFragment()를 호출합니다. FragmentScenario는 이 유형의 프래그먼트를 완전히 비어 있는 활동(루트 뷰가 없는 활동)에 연결합니다.

이러한 프래그먼트 유형 중 하나의 실행을 시작한 후에는 FragmentScenario가 테스트 중인 프래그먼트를 RESUMED 상태로 변경합니다. 이 상태는 프래그먼트가 실행 중이라는 것을 나타냅니다. 그래픽 프래그먼트를 테스트하고 있으면 사용자에게도 표시되므로 Espresso UI 테스트를 사용하여 UI 요소에 관한 정보를 평가할 수 있습니다.

다음 코드 스니펫은 각 유형의 프래그먼트를 실행하는 방법을 보여줍니다.

그래픽 프래그먼트 예

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEventFragment() {
            // The "fragmentArgs" 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!")))
        }
    }
    

그래픽이 아닌 프래그먼트 예

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

프래그먼트 다시 만들기

기기의 리소스가 부족하면 시스템에서 프래그먼트가 포함된 활동을 제거할 수 있습니다. 따라서 사용자가 앱으로 돌아올 때 앱이 프래그먼트를 다시 만들어야 할 수 있습니다. 이러한 상황을 시뮬레이션하려면 recreate()를 호출합니다.

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

FragmentScenario 클래스가 테스트 중인 프래그먼트를 다시 만들면 프래그먼트는 다시 만들어지기 전 수명 주기 상태로 돌아갑니다.

프래그먼트를 새로운 상태로 변경

앱의 UI 테스트에서는 테스트 중인 프래그먼트를 실행하고 다시 만드는 것만으로 충분한 경우가 많습니다. 그러나 세분화된 단위 테스트에서는 프래그먼트가 한 수명 주기 상태에서 다른 수명 주기 상태로 전환될 때 프래그먼트의 동작을 평가할 수도 있습니다.

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

moveToState()의 사용 예는 다음 코드 스니펫에 나와 있습니다.

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

프래그먼트에서 작업 트리거

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

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

프래그먼트 자체에서 메서드를 호출해야 할 경우(예: 옵션 메뉴에서의 선택에 응답) 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.
                }
            }
        }
    }
    

대화상자 작업 테스트

FragmentScenario대화상자 테스트도 지원합니다. 대화상자가 그래픽 프래그먼트의 인스턴스인 경우에도 launchFragment() 메서드를 사용하여 대화상자를 실행하는 활동이 아니라 대화상자 자체에 대화상자의 요소가 채워지도록 합니다.

다음 코드 스니펫은 대화상자 닫기 프로세스를 테스트합니다.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testDismissDialogFragment() {
            // Assumes that "MyDialogFragment" extends the DialogFragment class.
            with(launchFragment<MyDialogFragment>()) {
                onFragment { fragment ->
                    assertThat(fragment.dialog).isNotNull()
                    assertThat(fragment.requireDialog().isShowing).isTrue()
                    fragment.dismiss()
                    fragment.requireFragmentManager().executePendingTransactions()
                    assertThat(fragment.dialog).isNull()
                }

                // Assumes that the dialog had a button
                // containing the text "Cancel".
                onView(withText("Cancel")).check(doesNotExist())
            }
        }
    }