Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

탐색 테스트

애플리케이션이 예상대로 작동하는지 확인하기 위해 출시 전에 앱의 탐색 로직을 테스트해야 합니다.

탐색 구성요소는 대상 간의 탐색 관리, 매개변수 전달 및 FragmentManager 사용에 관계된 모든 작업을 처리합니다. 이러한 기능은 이미 엄격하게 테스트되었으므로 앱에서 다시 테스트할 필요는 없습니다. 그러나 테스트해야 하는 중요한 부분은 프래그먼트와 NavController의 앱 관련 코드 간의 상호작용입니다. 이 가이드에서는 몇 가지 일반적인 탐색 시나리오와 시나리오를 테스트하는 방법에 관해 설명합니다.

프래그먼트 탐색 테스트

NavController를 사용하여 독립적으로 프래그먼트 상호작용을 테스트하려면 Mockito를 사용하여 테스트 내에 가상 를 제공하면 됩니다. 그런 다음 가상 구현을 사용하여 가상 구현과의 상호작용을 확인할 수 있습니다.

예를 들어 퀴즈 게임을 빌드하고 있다고 가정해 보겠습니다. 게임은 title_screen으로 시작하고 사용자가 Play를 클릭하면 in_game 화면으로 이동합니다.

title_screen을 나타내는 프래그먼트는 다음과 같습니다.

Kotlin

    class TitleScreen : Fragment() {
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ) = inflater.inflate(R.layout.fragment_title_screen, container, false)

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            view.findViewById<Button>(R.id.play_btn).setOnClickListener {
                view.findNavController().navigate(R.id.action_title_screen_to_in_game)
            }
        }
    }
    

자바

    public class TitleScreen extends Fragment {

        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater,
                @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_title_screen, container, false);
        }

        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            view.findViewById(R.id.play_btn).setOnClickListener(v -> {
                Navigation.findNavController(view).navigate(R.id.action_title_screen_to_in_game);
            });
        }
    }
    

사용자가 Play를 클릭했을 때 앱에서 사용자가 in_game 화면으로 적절하게 이동하도록 하는지 테스트하려면 테스트에서 이 프래그먼트가 R.id.action_title_screen_to_in_game 작업을 사용하여 NavController.navigate()를 호출하는지 확인해야 합니다.

FragmentScenario, Espresso 및 Mockito의 조합을 사용하여 아래와 같이 이 시나리오를 테스트하는 데 필요한 조건을 다시 만들 수 있습니다.

Kotlin

    @RunWith(AndroidJUnit4::class)
    class TitleScreenTest {

        @Test
        fun testNavigationToInGameScreen() {
            // Create a mock NavController
            val mockNavController = mock(NavController::class.java)

            // Create a graphical FragmentScenario for the TitleScreen
            val titleScenario = launchFragmentInContainer<TitleScreen>()

            // Set the NavController property on the fragment
            titleScenario.onFragment { fragment ->
                Navigation.setViewNavController(fragment.requireView(), mockNavController)
            }

            // Verify that performing a click prompts the correct Navigation action
            onView(ViewMatchers.withId(R.id.play_btn)).perform(ViewActions.click())
            verify(mockNavController).navigate(R.id.action_title_screen_to_in_game)
        }
    }
    

자바

    @RunWith(AndroidJUnit4.class)
    public class TitleScreenTestJava {

        @Test
        public void testNavigationToInGameScreen() {

            // Create a mock NavController
            NavController mockNavController = mock(NavController.class);

            // Create a graphical FragmentScenario for the TitleScreen
            FragmentScenario<TitleScreen> titleScenario = FragmentScenario.launchInContainer(TitleScreen.class);

            // Set the NavController property on the fragment
            titleScenario.onFragment(fragment ->
                    Navigation.setViewNavController(fragment.requireView(), mockNavController)
            );

            // Verify that performing a click prompts the correct Navigation action
            onView(ViewMatchers.withId(R.id.play_btn)).perform(ViewActions.click());
            verify(mockNavController).navigate(R.id.action_title_screen_to_in_game);
        }
    }
    

위의 예에서는 NavController의 가상 인스턴스를 만들어 프래그먼트에 할당합니다. 그런 다음 Espresso를 사용하여 UI를 만들고 적절한 탐색 작업이 실행되는지 확인합니다.

FragmentScenario로 NavigationUI 테스트

앞의 예에서 titleScenario.onFragment()에 제공된 콜백은 프래그먼트가 수명 주기를 통해 RESUMED 상태로 이동한 후에 호출됩니다. 이때 프래그먼트의 뷰는 이미 생성되고 연결되었기 때문에 수명 주기에서 너무 늦어 적절한 테스트가 어려울 수 있습니다. 예를 들어, 프래그먼트에서 제어하는 Toolbar와 같은 NavigationUI를 프래그먼트에서 뷰와 함께 사용하면 프래그먼트가 RESUMED 상태에 도달하기 전에 NavController를 사용하여 설정 메서드를 호출할 수 있습니다. 따라서, 수명 주기 초기에 가상 NavController를 설정하는 방법이 필요합니다.

자체 Toolbar를 갖는 프래그먼트는 다음과 같이 작성하면 됩니다.

Kotlin

    class TitleScreen : Fragment() {

        override fun onCreateView(
                inflater: LayoutInflater,
                container: ViewGroup?,
                savedInstanceState: Bundle?
        ) = return inflater.inflate(R.layout.fragment_title_screen, container, false)

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            val navController = view.findNavController()
            view.findViewById<Toolbar>(R.id.toolbar).setupWithNavController(navController)
        }
    }
    

자바

    public class TitleScreen extends Fragment {

        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater,
                @Nullable ViewGroup container,
                @Nullable Bundle savedInstanceState) {
           return inflater.inflate(R.layout.fragment_title_screen, container, false);
        }

        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            NavController navController = Navigation.findNavController(view);
            view.findViewById(R.id.toolbar).setupWithNavController(navController);
        }
    }
    

여기에서 onViewCreated()가 호출될 때 가상으로 구현된 NavController가 필요합니다. onFragment()의 이전 접근 방식을 사용하면 가상 NavController를 설정이 수명 주기에서 너무 늦어 findNavController() 호출이 실패합니다.

FragmentScenario는 수명 주기 이벤트에 콜백을 등록하는 데 사용할 수 있는 FragmentFactory 인터페이스를 제공합니다. 아래 예와 같이 이 클래스는 Fragment.getViewLifecycleOwnerLiveData()와 결합하여 onCreateView()에 곧바로 뒤따라오는 콜백을 수신할 수 있습니다.

Kotlin

    val scenario = launchFragmentInContainer {
        TitleScreen().also { fragment ->

            // In addition to returning a new instance of our Fragment,
            // get a callback whenever the fragment’s view is created
            // or destroyed so that we can set the mock NavController
            fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
                if (viewLifecycleOwner != null) {
                    // The fragment’s view has just been created
                    Navigation.setViewNavController(fragment.requireView(), mockNavController)
                }
            }
        }
    }
    

자바

    FragmentScenario<TitleScreen> scenario =
    FragmentScenario.launchInContainer(
           TitleScreen.class, null, new FragmentFactory() {
        @NonNull
        @Override
        public Fragment instantiate(@NonNull ClassLoader classLoader,
                @NonNull String className,
                @Nullable Bundle args) {
            TitleScreen titleScreen = new TitleScreen();

            // In addition to returning a new instance of our fragment,
            // get a callback whenever the fragment’s view is created
            // or destroyed so that we can set the mock NavController
            titleScreen.getViewLifecycleOwnerLiveData().observeForever(new Observer<LifecycleOwner>() {
                @Override
                public void onChanged(LifecycleOwner viewLifecycleOwner) {

                    // The fragment’s view has just been created
                    if (viewLifecycleOwner != null) {
                        Navigation.setViewNavController(titleScreen.requireView(), mockNavController);
                    }

                }
            });
            return titleScreen;
        }
    });
    

이 기법을 사용하면 onViewCreated()가 호출되기 전에 NavController를 사용할 수 있으며 프래그먼트가 비정상 종료되지 않고 NavigationUI 메서드를 사용할 수 있습니다.

  • 계측 단위 테스트 빌드 - 계측 테스트 도구 모음의 설정 방법과 Android 기기에서 테스트를 실행하는 방법을 알아봅니다.
  • Espresso - Espresso로 앱 UI를 테스트합니다.
  • AndroidX 테스트로 JUnit4 규칙 사용 - AndroidX 테스트 라이브러리에서 JUnit 4 규칙을 사용하여 유연성을 높이고 테스트에서 필요한 상용구 코드를 줄입니다.
  • 앱 프래그먼트 테스트 - FragmentScenario를 사용하여 독립적으로 앱 프래그먼트를 테스트하는 방법을 배웁니다.
  • AndroidX Test용 프로젝트 설정 - AndroidX 테스트를 사용하기 위해 앱 프로젝트 파일에 필요한 라이브러리를 선언하는 방법을 배웁니다.