ऐप्लिकेशन को शिप करने से पहले, उसके नेविगेशन लॉजिक की जांच करना ज़रूरी है. इससे यह पुष्टि की जा सकती है कि आपका ऐप्लिकेशन आपकी उम्मीद के मुताबिक काम कर रहा है.
नेविगेशन कॉम्पोनेंट, डेस्टिनेशन के बीच नेविगेशन मैनेज करने, आर्ग्युमेंट पास करने, और FragmentManager के साथ काम करने से जुड़े सभी काम करता है. इन सुविधाओं की पहले ही अच्छी तरह से जांच की जा चुकी है. इसलिए, आपको अपने ऐप्लिकेशन में इनकी फिर से जांच करने की ज़रूरत नहीं है. हालांकि, यह जांच करना ज़रूरी है कि आपके फ़्रैगमेंट में मौजूद ऐप्लिकेशन के हिसाब से कोड और उनके NavController के बीच इंटरैक्शन कैसा है.
अलग से टेस्ट करना
फ़्रैगमेंट इंटरैक्शन को उनके NavController के साथ अलग से टेस्ट करने के लिए, Navigation 2.3 और इसके बाद के वर्शन में TestNavHostController उपलब्ध है. यह NavController.navigate() कार्रवाइयों के बाद, मौजूदा डेस्टिनेशन सेट करने और बैक स्टैक की पुष्टि करने के लिए एपीआई उपलब्ध कराता है.
अपने प्रोजेक्ट में Navigation Testing आर्टफ़ैक्ट जोड़ने के लिए, अपने ऐप्लिकेशन मॉड्यूल की build.gradle फ़ाइल में यह डिपेंडेंसी जोड़ें:
Groovy
dependencies { def nav_version = "2.9.8" androidTestImplementation "androidx.navigation:navigation-testing:$nav_version" }
Kotlin
dependencies { val nav_version = "2.9.8" 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 using 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
fun 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 using 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 की तरह, TestNavHostController को चालू करने के लिए, आपको setGraph को कॉल करना होगा. इस उदाहरण में, जिस फ़्रैगमेंट की जांच की जा रही है वह हमारे ग्राफ़ का शुरुआती डेस्टिनेशन था. TestNavHostController, setCurrentDestination तरीका उपलब्ध कराता है. इसकी मदद से, मौजूदा डेस्टिनेशन (और चाहें, तो उस डेस्टिनेशन के लिए आर्ग्युमेंट) सेट किया जा सकता है. इससे, आपका टेस्ट शुरू होने से पहले NavController सही स्थिति में होता है.
NavHostFragment के जिस इंस्टेंस का इस्तेमाल NavHostFragment करता है उससे अलग, TestNavHostController, navigate() को कॉल करने पर, navigate() के बुनियादी व्यवहार (जैसे कि FragmentTransaction, जो FragmentNavigator करता है) को ट्रिगर नहीं करता. यह सिर्फ़ TestNavHostController की स्थिति को अपडेट करता है.NavHostController
FragmentScenario की मदद से NavigationUI को टेस्ट करना
ऊपर दिए गए उदाहरण में, titleScenario.onFragment() को दिया गया कॉलबैक तब कॉल किया जाता है, जब फ़्रैगमेंट अपने लाइफ़साइकल के दौरान RESUMED स्थिति में पहुंच जाता है. इस समय तक, फ़्रैगमेंट का व्यू पहले ही बन चुका होता है और अटैच हो चुका होता है. इसलिए, सही तरीके से टेस्ट करने के लिए, लाइफ़साइकल में बहुत देर हो सकती है. उदाहरण के लिए, जब फ़्रैगमेंट में व्यू के साथ NavigationUI का इस्तेमाल किया जाता है, जैसे कि आपके फ़्रैगमेंट से कंट्रोल किए जाने वाले Toolbar के साथ, तब फ़्रैगमेंट के RESUMED स्थिति में पहुंचने से पहले, अपने NavController के साथ सेटअप करने के तरीकों को कॉल किया जा सकता है. इसलिए, आपको लाइफ़साइकल में पहले ही 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);
}
}
यहां हमें NavController की ज़रूरत है, जिसे onViewCreated() को कॉल किए जाने से पहले बनाया गया हो. 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;
}
});
इस तकनीक का इस्तेमाल करने से, onViewCreated() को कॉल करने से पहले NavController उपलब्ध हो जाता है. इससे फ़्रैगमेंट, क्रैश हुए बिना NavigationUI तरीकों का इस्तेमाल कर पाता है.
बैक स्टैक एंट्री के साथ इंटरैक्शन की जांच करना
बैक स्टैक एंट्री के साथ इंटरैक्ट करते समय, TestNavHostController की मदद से कंट्रोलर को अपने टेस्ट LifecycleOwner, ViewModelStore, और OnBackPressedDispatcher से कनेक्ट किया जा सकता है. इसके लिए, NavHostController से इनहेरिट किए गए एपीआई का इस्तेमाल किया जाता है.
उदाहरण के लिए, नेविगेशन स्कोप वाले ViewModel का इस्तेमाल करने वाले फ़्रैगमेंट की जांच करते समय, आपको TestNavHostController पर setViewModelStore को कॉल करना होगा:
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())
मिलते-जुलते विषय
- इंस्ट्रुमेंट की गई यूनिट टेस्ट बनाना - इंस्ट्रुमेंट की गई टेस्ट सुइट सेट अप करने और Android डिवाइस पर टेस्ट चलाने का तरीका जानें.
- Espresso - Espresso की मदद से, अपने ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) की जांच करें.
- AndroidX Test के साथ JUnit4 के नियम - AndroidX Test लाइब्रेरी के साथ JUnit 4 के नियमों का इस्तेमाल करें. इससे आपको ज़्यादा सुविधा मिलती है और टेस्ट में ज़रूरी बॉयलरप्लेट कोड कम हो जाता है.
- अपने ऐप्लिकेशन के फ़्रैगमेंट टेस्ट करना - जानें कि
FragmentScenarioकी मदद से, अपने ऐप्लिकेशन के फ़्रैगमेंट को अलग से कैसे टेस्ट किया जाता है. - AndroidX Test के लिए प्रोजेक्ट सेट अप करना - AndroidX Test का इस्तेमाल करने के लिए, अपने ऐप्लिकेशन के प्रोजेक्ट फ़ाइलों में ज़रूरी लाइब्रेरी का एलान करने का तरीका जानें.