Синхронизируйте свои тесты

Тесты Compose синхронизируются по умолчанию с вашим UI. Когда вы вызываете утверждение или действие с ComposeTestRule , тест синхронизируется заранее, ожидая, пока дерево UI не станет бездействующим.

Обычно вам не нужно предпринимать никаких действий. Однако есть некоторые крайние случаи, о которых вам следует знать.

Когда тест синхронизирован, ваше приложение Compose продвигается во времени с помощью виртуальных часов. Это означает, что тесты Compose не выполняются в реальном времени, поэтому они могут проходить как можно быстрее.

Однако если вы не используете методы синхронизации тестов, рекомпозиция не произойдет, а пользовательский интерфейс будет выглядеть приостановленным.

@Test
fun counterTest() {
    val myCounter = mutableStateOf(0) // State that can cause recompositions.
    var lastSeenValue = 0 // Used to track recompositions.
    composeTestRule.setContent {
        Text(myCounter.value.toString())
        lastSeenValue = myCounter.value
    }
    myCounter.value = 1 // The state changes, but there is no recomposition.

    // Fails because nothing triggered a recomposition.
    assertTrue(lastSeenValue == 1)

    // Passes because the assertion triggers recomposition.
    composeTestRule.onNodeWithText("1").assertExists()
}

Обратите внимание, что это требование применяется только к иерархиям Compose, а не к остальной части приложения.

Отключить автоматическую синхронизацию

Когда вы вызываете утверждение или действие через ComposeTestRule , например assertExists() , ваш тест синхронизируется с Compose UI. В некоторых случаях вы можете захотеть остановить эту синхронизацию и управлять часами самостоятельно. Например, вы можете управлять временем, чтобы делать точные снимки экрана анимации в точке, где UI все еще будет занят. Чтобы отключить автоматическую синхронизацию, установите свойство autoAdvance в mainClock в false :

composeTestRule.mainClock.autoAdvance = false

Обычно вы затем сами продвигаете время. Вы можете продвигать его ровно на один кадр с помощью advanceTimeByFrame() или на определенную длительность с помощью advanceTimeBy() :

composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)

Неиспользуемые ресурсы

Compose может синхронизировать тесты и пользовательский интерфейс, так что каждое действие и утверждение выполняется в состоянии ожидания, ожидая или продвигая часы по мере необходимости. Однако некоторые асинхронные операции, результаты которых влияют на состояние пользовательского интерфейса, могут выполняться в фоновом режиме, пока тест не знает о них.

Создайте и зарегистрируйте эти ресурсы бездействия в вашем тесте, чтобы они учитывались при принятии решения о том, занято или бездействует тестируемое приложение. Вам не нужно предпринимать никаких действий, если только вам не нужно регистрировать дополнительные ресурсы бездействия, например, если вы запускаете фоновое задание, которое не синхронизировано с Espresso или Compose.

Этот API очень похож на Idling Resources Espresso, чтобы указать, является ли тестируемый субъект бездействующим или занятым. Используйте тестовое правило Compose для регистрации реализации IdlingResource .

composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)

Ручная синхронизация

В некоторых случаях вам придется синхронизировать Compose UI с другими частями вашего теста или тестируемого вами приложения.

Функция waitForIdle() ожидает, пока Compose перейдет в режим ожидания, но функция зависит от свойства autoAdvance :

composeTestRule.mainClock.autoAdvance = true // Default
composeTestRule.waitForIdle() // Advances the clock until Compose is idle.

composeTestRule.mainClock.autoAdvance = false
composeTestRule.waitForIdle() // Only waits for idling resources to become idle.

Обратите внимание, что в обоих случаях waitForIdle() также ожидает завершения проходов отрисовки и макета .

Кроме того, с помощью advanceTimeUntil() можно перевести часы вперед до тех пор, пока не будет выполнено определенное условие.

composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }

Обратите внимание, что данное условие должно проверять состояние, на которое могут влиять эти часы (работает только с состоянием Compose).

Ждать условий

Любое условие, зависящее от внешней работы, например, загрузки данных или измерения или рисования Android (то есть измерения или рисования, внешнего по отношению к Compose), должно использовать более общую концепцию, например waitUntil() :

composeTestRule.waitUntil(timeoutMs) { condition }

Вы также можете использовать любой из помощников waitUntil :

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

Дополнительные ресурсы

  • Тестирование приложений на Android : главная целевая страница тестирования Android предоставляет более широкий обзор основ и методов тестирования.
  • Основы тестирования : узнайте больше об основных концепциях тестирования приложений Android.
  • Локальные тесты : вы можете запустить некоторые тесты локально, на своей рабочей станции.
  • Инструментированные тесты : Хорошей практикой является также запуск инструментированных тестов. То есть тестов, которые запускаются непосредственно на устройстве.
  • Непрерывная интеграция : Непрерывная интеграция позволяет интегрировать ваши тесты в конвейер развертывания.
  • Тестируйте разные размеры экранов : поскольку пользователям доступно множество устройств, вам следует тестировать экраны разных размеров.
  • Espresso : хотя знание Espresso и предназначено для пользовательских интерфейсов на основе View, оно все равно может быть полезно для некоторых аспектов тестирования Compose.