Compose интегрируется с распространенными фреймворками тестирования.
Совместимость с Espresso
В гибридном приложении компоненты Compose могут находиться в иерархиях View, а View – в composable-функциях Compose (через composable-функцию AndroidView).
Для сопоставления любого из этих типов не требуется никаких специальных действий. Вы сопоставляете представления с помощью onView Espresso, а элементы Compose – с помощью ComposeTestRule.
@Test
fun androidViewInteropTest() {
// Check the initial state of a TextView that depends on a Compose state.
Espresso.onView(withText("Hello Views")).check(matches(isDisplayed()))
// Click on the Compose button that changes the state.
composeTestRule.onNodeWithText("Click here").performClick()
// Check the new value.
Espresso.onView(withText("Hello Compose")).check(matches(isDisplayed()))
}
Как добавить семантику View-scoped для тестирования совместимости Compose
Как ограничить поиск в Compose определенными представлениями
При переносе сложных пользовательских интерфейсов в Compose вы можете столкнуться с идентичными элементами Compose, вложенными в несколько традиционных представлений Android, например в RecyclerView или ViewPager. В таких случаях стандартный поиск Compose, например onNodeWithText("Save"), может завершиться ошибкой "Найдено несколько узлов".
Вместо того чтобы изменять рабочий код для внедрения динамических тестовых тегов, чтобы различать эти элементы, вы можете ограничить область действия теста Compose непосредственно определенным представлением Android.
Используйте onRootWithViewInteraction API для тестового правила. Эта функция принимает Espresso ViewInteraction, позволяя вам использовать Espresso для изоляции определенного контейнера View и выполнения взаимодействий Compose исключительно в этой иерархии.
Как взаимодействовать с элементом списка
Если вам нужно взаимодействовать с элементом Compose в определенной строке RecyclerView, найдите ее с помощью Espresso, а затем ограничьте взаимодействие с Compose этой строкой.
Идентичные элементы Compose во всех остальных строках игнорируются.
@Test fun testComposeButtonInsideRecyclerViewItem() = runComposeUiTest { // Scroll to the desired position using Espresso Espresso.onView(withId(recyclerViewId)) .perform(RecyclerViewActions.scrollToPosition<MyViewHolder>(3)) // Define an Espresso ViewInteraction that uniquely identifies the row val rowView = Espresso.onView( allOf( withId(rootViewId), hasDescendant(withText("Item #3")) ) ) // Scope the Compose search strictly to that specific row View onRootWithViewInteraction(rowView) .onNode(hasText("Like")) .performClick() }
Устранение неоднозначности в ViewPager
Если в памяти одновременно находится несколько фрагментов с идентичными макетами Compose, вы можете ограничить область поиска идентификатором корневого представления определенного фрагмента, чтобы избежать неоднозначности совпадений.
@Test fun testComposeButtonInsideViewPagerItem() = runComposeUiTest { // Swipe to the desired page using Espresso Espresso.onView(withId(viewPagerViewId)).perform(swipeLeft()) // Identify the specific container view using Espresso val fragmentB = Espresso.onView(withId(fragmentRootViewId)) // The generic text "Save" is now unique within this view scope onRootWithViewInteraction(fragmentB) .onNode(hasText("Save")) .assertIsDisplayed() }
Совместимость с UiAutomator
По умолчанию компоненты доступны из UiAutomator только по их дескрипторам (отображаемый текст, описание контента и т. д.). Если вы хотите получить доступ к любой composable-функции, которая использует Modifier.testTag, вам нужно включить семантическое свойство testTagsAsResourceId для поддерева этой функции. Это полезно для composable-функций, у которых нет других уникальных дескрипторов, например для прокручиваемых composable-функций (таких как LazyColumn).
Включите семантическое свойство только один раз в верхней части иерархии composable-функций, чтобы обеспечить доступность всех вложенных composable-функций с Modifier.testTag из UiAutomator.
Scaffold(
// Enables for all composables in the hierarchy.
modifier = Modifier.semantics {
testTagsAsResourceId = true
}
){
// Modifier.testTag is accessible from UiAutomator for composables nested here.
LazyColumn(
modifier = Modifier.testTag("myLazyColumn")
){
// Content
}
}
Любая composable-функция с Modifier.testTag(tag) может быть доступна с помощью By.res(resourceName), использующего тот же tag, что и resourceName.
val device = UiDevice.getInstance(getInstrumentation())
val lazyColumn: UiObject2 = device.findObject(By.res("myLazyColumn"))
// Some interaction with the lazyColumn.
Дополнительные ресурсы
- Тестирование приложений для Android. На этой целевой странице вы найдете общую информацию об основах и методах тестирования.
- Основы тестирования. Узнайте больше об основных концепциях тестирования приложений для Android.
- Локальные тесты. Некоторые тесты можно запускать локально на рабочей станции.
- Инструментальные тесты. Рекомендуем также проводить инструментальные тесты. То есть тесты, которые запускаются непосредственно на устройстве.
- Непрерывная интеграция. Непрерывная интеграция позволяет интегрировать тесты в конвейер развертывания.
- Тестируйте приложение на экранах разных размеров. Пользователи могут запускать приложение на самых разных устройствах.
- Espresso. Хотя этот инструмент предназначен для интерфейсов на основе представлений, он может быть полезен для некоторых аспектов тестирования Compose.