Uygulamanızın beklediğiniz gibi çalıştığını doğrulamak için ürünü göndermeden önce uygulamanızın gezinme mantığını test etmeniz önemlidir.
Gezinme bileşeni, Google Cloud Platform ile
hedefleri iletme, argümanları iletme ve
FragmentManager
.
Bu özellikler zaten titizlikle test edildiğinden test etmeye gerek yoktur
bunları uygulamanızda tekrar kullanabilirsiniz. Ancak test edilmesi gereken önemli nokta,
parçalarınızdaki uygulamaya özel kod ile bunların
NavController
.
Bu kılavuzda, sık karşılaşılan birkaç gezinme senaryosu ve bunların nasıl test edileceği açıklanmaktadır.
Parça gezinmeyi test et
NavController
ile parça etkileşimlerini ayrı ayrı test etmek için
Gezinme 2.3 ve üstü sürümler bir
TestNavHostController
Mevcut hedefi ayarlamak ve gerisini doğrulamak için API'ler
sonrasında yığınla
NavController.navigate()
anlamına gelir.
uygulama modülünüzün build.gradle
dosyasında aşağıdaki bağımlılığı gösterilmektedir:
Groovy
dependencies { def nav_version = "2.7.7" androidTestImplementation "androidx.navigation:navigation-testing:$nav_version" }
Kotlin
dependencies { val nav_version = "2.7.7" androidTestImplementation("androidx.navigation:navigation-testing:$nav_version") }
Bir bilgi yarışması oyunu geliştirdiğinizi varsayalım. Oyun şununla başlar: title_screen ve kullanıcı tıkladığında in_game ekranına gider oyna.
title_screen öğesini temsil eden parça şuna benzer şekilde görünebilir:
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); }); } }
Aşağıdaki işlemler yapıldığında uygulamanın kullanıcıyı in_game ekranına yönlendirip yönlendirmediğini test etmek için
kullanıcı Oynat'ı tıklarsa testinizin bu parçanın
NavController
öğesini R.id.in_game
ekranına doğru şekilde taşır.
FragmentScenario
, Espresso,
ve TestNavHostController
özelliklerini test etmek için gerekli koşulları yeniden
aşağıdaki örnekte gösterildiği gibi:
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); } }
Yukarıdaki örnek, bir TestNavHostController
örneği oluşturur ve bunu atar
temsil eder. Daha sonra, kullanıcı arayüzünü çalıştırmak için Espresso'yu kullanır ve
ve uygun gezinme işleminin gerçekleştirildiği anlamına gelir.
Gerçek bir NavController
gibi, başlatmak için setGraph
çağrısı yapmanız gerekir
TestNavHostController
. Bu örnekte, test edilen parça
grafiğimizin başlangıç noktasıdır. TestNavHostController
,
setCurrentDestination
geçerli hedefi (ve isteğe bağlı olarak
bağımsız değişkenlerini) kullanarak NavController
nesnesinin
doğru duruma getirin.
NavHostFragment
öğesinin kullanacağı NavHostController
örneğinden farklı olarak,
TestNavHostController
, temel navigate()
öğesini tetiklemez
davranışı (FragmentNavigator
tarafından yapılan FragmentTransaction
gibi)
navigate()
çağrıldığında, yalnızca
TestNavHostController
.
FragmentScenario ile Gezinme Arayüzünü Test Etme
Önceki örnekte, titleScenario.onFragment()
adlı kullanıcıya sağlanan geri çağırma
, parça, yaşam döngüsünden şuraya taşındıktan sonra çağrılır:
RESUMED
durumu. Bu ana kadar, parçanın görünümü oluşturulmuş ve eklenmiş,
Bu nedenle doğru şekilde test etmek için yaşam döngüsünde çok geç olabilir. Örneğin,
Parçanızda görünümlere sahip NavigationUI
(ör. Toolbar
kontrolünde olanlar)
için, kurulumdan önce NavController
ile kurulum yöntemlerini çağırabilirsiniz.
parça RESUMED
durumuna ulaşır. Bu nedenle, ayarlarınızı yönetmenin bir yolunu
TestNavHostController
daha erken.
Kendi Toolbar
öğesine sahip olan bir parça aşağıdaki gibi yazılabilir:
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); } }
Burada, onViewCreated()
çağrıldığında oluşturulan NavController
öğesine ihtiyacımız var.
Önceki onFragment()
yaklaşımını kullanmak TestNavHostController
çok geç olduğundan findNavController()
çağrısı başarısız olabilir.
FragmentScenario
şunları sunar:
FragmentFactory
yaşam döngüsü olayları için geri çağırmaların kaydedilmesinde kullanılan bir arayüz oluşturur. Bu
almak için Fragment.getViewLifecycleOwnerLiveData()
ile birleştirilir
aşağıdaki gibi onCreateView()
hemen sonra gelen geri çağırma
örnek:
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; } });
Bu teknik kullanıldığında NavController
,
onViewCreated()
çağrılır ve parçanın NavigationUI
yöntemleri kullanmasına izin verilir
hale getirir.
Geri yığın girişleriyle etkileşimleri test etme
Geri yığın girişleriyle etkileşimde bulunurken,
TestNavHostController
, kumandayı kendi cihazınıza bağlamanıza olanak tanır.
LifecycleOwner
, ViewModelStore
ve OnBackPressedDispatcher
özelliklerini test etmek için
devraldığı API'leri kullanarak
NavHostController
.
Örneğin,
navigasyon kapsamlı ViewModel,
araman lazım
setViewModelStore
TestNavHostController
tarihinde:
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())
İlgili konular
- Araçlı birim testleri oluşturun - Araçlı test paketinizi nasıl ayarlayacağınızı ve Android'de nasıl test çalıştıracağınızı öğrenin olanak tanır.
- Espresso - Uygulamanızın kullanıcı arayüzünü test edin tercih edebilirsiniz.
- AndroidX Test ile JUnit4 kuralları - JUnit 4'ü kullanın kurallarını AndroidX Test kitaplıklarıyla birleştirerek daha fazla esneklik sağlar ve daha az testlerde gerekli olan ortak metin kodu.
- Uygulamanızın parçalarını test etme -
Uygulama parçalarınızı
FragmentScenario
ile ayrı olarak nasıl test edeceğinizi öğrenin. - AndroidX Test için proje oluşturun - Öğrenin AndroidX kullanmak için uygulamanızın proje dosyalarında gerekli kitaplıkları bildirme Test et.