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

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

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

Когда тест синхронизируется, ваше приложение 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. В некоторых случаях вам может потребоваться остановить эту синхронизацию и самостоятельно управлять часами. Например, вы можете контролировать время, чтобы делать точные снимки экрана анимации в тот момент, когда пользовательский интерфейс все еще занят. Чтобы отключить автоматическую синхронизацию, установите для свойства 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 с другими частями вашего теста или тестируемого приложения.

Функция 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.