Базовое тестирование NavigationController в Android

#android #testing #android-espresso #instrumented-test

#Android #тестирование #android-espresso #инструментальный-тест

Вопрос:

В настоящее время я новичок в тестировании, поэтому решил начать с некоторых базовых вещей.

Я обрабатываю все свои навигации из DrawerLayout, который связан с действием.

Итак, для моего тестирования я запускаю ActivityScenarioRule, создаю объект testNavController, а затем устанавливаю этот testNavController в текущее представление, которое обрабатывает навигацию (фрагмент контейнера).

Таким образом, тест состоит в том, чтобы открыть ящик, щелкнуть по пункту меню (перейти к фрагменту) и, следовательно, проверить, перешел ли он к фрагменту.

Затем я проверяю, произошло ли это, но testNavController остается в том же месте назначения, что странно, потому что он выполняет щелчок, поэтому я решил проверить NavController (реальный внутри activity), и он показывает мне, что перешел к правильному фрагменту.

Вот необходимый код:

 @LargeTest
@RunWith(AndroidJUnit4::class)
class MapsActivityTest {
    @get:Rule
    var activityScenarioRule = ActivityScenarioRule(MapsActivity::class.java)

    @Test
    fun clickOnDrawerMaps_NavigateToAboutAppFragment() {
        //Create TestNavHostController
        val testNavController = TestNavHostController(ApplicationProvider.getApplicationContext())

        UiThreadStatement.runOnUiThread { // This needed because it throws a exception that method addObserver must be called in main thread
            testNavController.setGraph(R.navigation.nav_graph)
        }
        
        val scenario = activityScenarioRule.scenario
        var navcontroller : NavController? = null
        scenario.onActivity {mapsActivity ->
            navcontroller = mapsActivity.navController //Get the real navController just to debug
            mapsActivity.navController = testNavController //Set the test navController
            Navigation.setViewNavController(mapsActivity.binding.containerFragment, testNavController)
        }

        onView(withId(R.id.drawerLayout)).perform(DrawerActions.open()).check(matches(isOpen()))
        onView(withId(R.id.aboutAppFragment)).perform(click())
        assertThat(testNavController.currentDestination?.id).isEqualTo(R.id.aboutAppFragment)
    }
}
 

В примере они используют фрагмент, для которого они устанавливают fragment.requireView() при запуске фрагмента, но я думаю, что это точно то же самое.

Что я здесь делаю не так?

Комментарии:

1. Есть ли причина TestNavHostController , по которой вы вообще используете a, если ваша активность уже имеет real NavController ?

2. Мое предположение, когда я начал тестирование, состояло в том, чтобы использовать что-то «поддельное» при тестировании вместо «реального» только для улучшения практики, но я снова только начал с тестирования, и я супер невежественен! Итак, я предполагаю, что мы устанавливаем TestNavController только при использовании фрагментов, потому что activity пуста, верно? @ianhanniballake

Ответ №1:

Когда вы используете ActivityScenario (или ActivityScenarioRule ), ваша активность полностью переводится в возобновленное состояние, прежде onActivity чем будут сделаны какие-либо вызовы. Это означает , что ваш реальный NavController уже создан и используется при вызове setupWithNavController . Вот почему ваш призыв к setViewNavController() не имеет никакого эффекта.

Для этих типов интеграционных тестов (где у вас есть real NavController ) вы не должны использовать TestNavHostController .

Согласно руководству по навигации по тестированию, TestNavHostController предназначен для модульных тестов, в которых у вас вообще нет реального NavController , например, при изолированном тестировании одного фрагмента.

Комментарии:

1. Теперь это имеет большой смысл! Большое вам спасибо за ваше объяснение 🙂