नेविगेशन की जांच करें

ऐप्लिकेशन शिप करने से पहले, उसके नेविगेशन लॉजिक की जांच करना ज़रूरी है. इससे यह पुष्टि की जा सकती है कि आपका ऐप्लिकेशन आपकी उम्मीद के मुताबिक काम कर रहा है या नहीं.

नेविगेशन कॉम्पोनेंट, नेविगेशन को मैनेज करने का सारा काम डेस्टिनेशन, आर्ग्युमेंट पास करना, और FragmentManager. इन क्षमताओं की पहले ही अच्छी तरह से जांच कर ली गई है, इसलिए इनकी ज़रूरत नहीं है उन्हें फिर से अपने ऐप्लिकेशन में जोड़ सकते हैं. हालांकि, टेस्ट करना ज़रूरी है कि इंटरैक्शन आपके फ़्रैगमेंट में ऐप्लिकेशन के खास कोड और उनके NavController. इस गाइड में नेविगेशन के कुछ आम तरीकों और उनकी जांच करने के तरीके के बारे में बताया गया है.

फ़्रैगमेंट नेविगेशन की जांच करना

फ़्रैगमेंट इंटरैक्शन को NavController के साथ अकेले टेस्ट करने के लिए, नेविगेशन 2.3 और उसके बाद के वर्शन में TestNavHostController जो मौजूदा डेस्टिनेशन को सेट करने के लिए एपीआई उपलब्ध कराता है और पिछले पेज की पुष्टि करता है इसके बाद स्टैक करें NavController.navigate() कार्रवाइयां.

आप आपके ऐप्लिकेशन मॉड्यूल की build.gradle फ़ाइल में, नीचे दी गई डिपेंडेंसी का इस्तेमाल किया जा रहा है:

Groovy

dependencies {
  def nav_version = "2.8.4"

  androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
}

Kotlin

dependencies {
  val nav_version = "2.8.4"

  androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")
}

मान लें कि आपको सवाल-जवाब वाला कोई गेम बनाना है. गेम इनसे शुरू होता है: title_screen और उपयोगकर्ता के क्लिक करने पर 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)
        }
    }
}

Java

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);
        });
    }
}

यह जांचने के लिए कि ऐप्लिकेशन उपयोगकर्ता को in_game स्क्रीन पर सही तरीके से नेविगेट करता है या नहीं अगर उपयोगकर्ता चलाएं पर क्लिक करता है, तो आपके टेस्ट को इस बात की पुष्टि करनी होगी कि यह फ़्रैगमेंट NavController को सही ढंग से R.id.in_game स्क्रीन पर ले जाता है.

FragmentScenario, Espresso, के कॉम्बिनेशन का इस्तेमाल करके, और TestNavHostController, तो टेस्ट के लिए ज़रूरी शर्तों को फिर से बनाया जा सकता है जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है:

Kotlin

@RunWith(AndroidJUnit4::class)
class TitleScreenTest {

    @Test
    fun testNavigationToInGameScreen() {
        // Create a TestNavHostController
        val navController = TestNavHostController(
            ApplicationProvider.getApplicationContext())

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

        titleScenario.onFragment { fragment ->
            // Set the graph on the TestNavHostController
            navController.setGraph(R.navigation.trivia)

            // Make the NavController available via the findNavController() APIs
            Navigation.setViewNavController(fragment.requireView(), navController)
        }

        // Verify that performing a click changes the NavController’s state
        onView(ViewMatchers.withId(R.id.play_btn)).perform(ViewActions.click())
        assertThat(navController.currentDestination?.id).isEqualTo(R.id.in_game)
    }
}

Java

@RunWith(AndroidJUnit4.class)
public class TitleScreenTestJava {

    @Test
    public void testNavigationToInGameScreen() {

        // Create a TestNavHostController
        TestNavHostController navController = new TestNavHostController(
            ApplicationProvider.getApplicationContext());

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

        titleScenario.onFragment(fragment ->
                // Set the graph on the TestNavHostController
                navController.setGraph(R.navigation.trivia);

                // Make the NavController available via the findNavController() APIs
                Navigation.setViewNavController(fragment.requireView(), navController)
        );

        // Verify that performing a click changes the NavController’s state
        onView(ViewMatchers.withId(R.id.play_btn)).perform(ViewActions.click());
        assertThat(navController.currentDestination.id).isEqualTo(R.id.in_game);
    }
}

ऊपर दिया गया उदाहरण, TestNavHostController का एक इंस्टेंस बनाता है और उसे असाइन करता है फ़्रैगमेंट तक पहुंच जाएंगे. इसके बाद यह यूज़र इंटरफ़ेस (यूआई) को चलाने के लिए Espresso का इस्तेमाल करती है और पुष्टि करती है कि नेविगेशन की ज़रूरी कार्रवाई की गई है.

बिलकुल असली NavController की तरह ही, शुरू करने के लिए आपको setGraph को कॉल करना होगा TestNavHostController. इस उदाहरण में, जिस खंड की जांच की जा रही है, वह था हमारे ग्राफ़ का शुरुआती गंतव्य होता है. TestNavHostController यह देता है: setCurrentDestination तरीका है जिससे आप मौजूदा डेस्टिनेशन (और वैकल्पिक रूप से, आर्ग्युमेंट के तौर पर शामिल करना होगा), ताकि NavController टेस्ट शुरू होने से पहले सही स्थिति सेट करें.

NavHostFragment का इस्तेमाल करने वाले NavHostController इंस्टेंस के उलट, TestNavHostController, मौजूदा navigate() को ट्रिगर नहीं करता है व्यवहार (जैसे कि FragmentTransaction जो FragmentNavigator करता है) जब आप navigate() को कॉल करते है - तो यह केवल TestNavHostController.

फ़्रैगमेंट स्थिति से नेविगेशन यूआई की जांच करें

पिछले उदाहरण में, titleScenario.onFragment() को दिया गया कॉलबैक तब कॉल किया जाता है, जब फ़्रैगमेंट अपने लाइफ़साइकल की मदद से RESUMED राज्य. तब तक, फ़्रैगमेंट का व्यू बन चुका होगा और अटैच हो चुका होगा, इसलिए, लाइफ़साइकल में शायद सही तरीके से टेस्ट न किया जा सके. उदाहरण के लिए, आपके फ़्रैगमेंट में व्यू वाले NavigationUI, जैसे कि Toolbar को कंट्रोल किया जाता है आपके फ़्रैगमेंट के आधार पर, अपने NavController की मदद से, सेटअप करने के तरीकों को कॉल किया जा सकता है फ़्रैगमेंट RESUMED स्थिति तक पहुंच जाता है. इसलिए, आपको अपना लक्ष्य सेट करने का लाइफ़साइकल में TestNavHostController पहले.

जिस फ़्रैगमेंट के पास अपने Toolbar का मालिकाना हक है उसे इस तरह लिखा जा सकता है:

Kotlin

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

Java

public class TitleScreen extends Fragment {
    public TitleScreen() {
        super(R.layout.fragment_title_screen);
    }

    @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() के पिछले तरीके का इस्तेमाल करने से, हमारी TestNavHostController सेट हो जाएगी बिलिंग साइकल में बहुत देर हो गई है, जिसकी वजह से 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 NavController
        fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
            if (viewLifecycleOwner != null) {
                // The fragment’s view has just been created
                navController.setGraph(R.navigation.trivia)
                Navigation.setViewNavController(fragment.requireView(), navController)
            }
        }
    }
}

Java

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 NavController
        titleScreen.getViewLifecycleOwnerLiveData().observeForever(new Observer<LifecycleOwner>() {
            @Override
            public void onChanged(LifecycleOwner viewLifecycleOwner) {

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

            }
        });
        return titleScreen;
    }
});

इस तकनीक का इस्तेमाल करने पर, NavController उपलब्ध हो जाता है onViewCreated() को कॉल किया गया है. इससे फ़्रैगमेंट को NavigationUI तरीकों का इस्तेमाल करने की अनुमति मिली है वह भी क्रैश हो गया.

पिछली गतिविधियों वाली एंट्री के साथ इंटरैक्शन की जांच करना

बैक स्टैक एंट्री के साथ इंटरैक्ट करते समय, TestNavHostController की मदद से, कंट्रोलर को अपने डिवाइस से कनेक्ट किया जा सकता है इसके हिसाब से LifecycleOwner, ViewModelStore, और OnBackPressedDispatcher की जांच करें इनहेरिट किए गए एपीआई का इस्तेमाल करके NavHostController.

उदाहरण के लिए, ऐसे फ़्रैगमेंट की जांच करते समय जो नेविगेशन के स्कोप वाला ViewModel, तुम्हें कॉल करना होगा setViewModelStore को TestNavHostController पर करें:

Kotlin

val navController = TestNavHostController(ApplicationProvider.getApplicationContext())

// This allows fragments to use by navGraphViewModels()
navController.setViewModelStore(ViewModelStore())

Java

TestNavHostController navController = new TestNavHostController(ApplicationProvider.getApplicationContext());

// This allows fragments to use new ViewModelProvider() with a NavBackStackEntry
navController.setViewModelStore(new ViewModelStore())