← Назад к вопросам

В чем разница между runBlockingTest, runTest и runBlocking?

2.0 Middle🔥 122 комментариев
#Многопоточность и асинхронность#Тестирование

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между runBlockingTest, runTest и runBlocking

В контексте Kotlin Coroutines для тестирования и разработки существует три основных функции, которые часто вызывают путаницу: runBlocking, runBlockingTest (устаревший) и runTest (современная замена). Все они предназначены для запуска корутин в синхронном стиле, но имеют разное предназначение и поведение.

runBlocking: для блокирующего запуска в продакшене

runBlocking — это базовая функция-строитель корутин, которая блокирует текущий поток до завершения всех запущенных внутри неё корутин. Она предназначена в основном для использования в продакшен-коде, например, в функциях main, тестах или при интеграции с блокирующим кодом.

import kotlinx.coroutines.*

fun main() {
    // Блокирует основной поток до выполнения корутины
    runBlocking {
        delay(1000L)
        println("Hello from runBlocking!")
    }
}
  • Ключевые особенности:
    *   Реальное ожидание (`delay` занимает реальное время).
    *   Не предназначена для тестирования (замедляет тесты).
    *   Использует настоящий диспетчер (если не указан иной).

runBlockingTest (устаревший): ускоренное тестирование (коревая библиотека)

runBlockingTest была экспериментальным API в kotlinx-coroutines-test и устарела в версии 1.6.0. Она создавала специальный TestCoroutineDispatcher и "виртуальное" время, позволяя пропускать задержки (delay) и мгновенно выполнять корутины.

// УСТАРЕВШИЙ ПРИМЕР (библиотека версии <1.6)
import kotlinx.coroutines.test.runBlockingTest

@Test
fun oldTest() = runBlockingTest { // Deprecated
    launch {
        delay(1000L) // Виртуальное время, выполняется мгновенно в тесте
        println("Immediate execution")
    }
    advanceTimeBy(1000L) // Управление виртуальным временем
}

runTest: современная замена для unit-тестов

Начиная с kotlinx-coroutines 1.6.0, runTest является полноценной заменой runBlockingTest. Она предоставляет те же возможности для управления временем, но построена на новой абстракции TestScope и использует StandardTestDispatcher.

import kotlinx.coroutines.test.runTest

@Test
fun modernTest() = runTest { // Рекомендуемый способ
    launch {
        delay(1000L) // Виртуальное время! Не ждем реальную секунду.
        println("Executed after virtual delay")
    }
    // Задержка не требуется, корутина запустится автоматически
    // или можно использовать advanceTimeBy(1000L)
}
  • Ключевые особенности runTest:
    *   **Виртуальное время**: `delay`, `withTimeout` выполняются мгновенно.
    *   **Контроль выполнения**: функции `advanceTimeBy`, `runCurrent`.
    *   **Чистота тестов**: автоматическая отмена незавершенных корутин после теста.
    *   Использует **TestScope** и **StandardTestDispatcher** "под капотом".


Сравнительная таблица

КритерийrunBlockingrunBlockingTest (устаревший)runTest (современный)
Основное назначениеПродакшен-код, main-функцииУстаревшие unit-тестыСовременные unit-тесты
Ожидание delayРеальное время (тест будет медленным)Виртуальное время (мгновенно)Виртуальное время (мгновенно)
Управление временемНетadvanceTimeBy, runCurrentadvanceTimeBy, runCurrent
Базовая архитектураEvent loopTestCoroutineDispatcher (устар.)TestScope + StandardTestDispatcher
Обработка паузРеальные паузыПропускались автоматическиТребует advanceUntilIdle или явного продвижения
РекомендацияИзбегать в unit-тестахНе использовать (Deprecated)Использовать для тестирования кода с корутинами

Практические рекомендации

  1. Для unit-тестов всегда используйте runTest. Он гарантирует скорость выполнения (исключая реальные задержки) и предоставляет полный контроль над виртуальным временем.
  2. runBlocking может использоваться в тестах интеграции или UI, где требуется реальное время, или при тестировании вместе с блокирующими библиотеками. Но для изолированных unit-тестов — это антипаттерн.
  3. При миграции с runBlockingTest на runTest обратите внимание на изменение поведения: runTest не продвигает время автоматически при запуске корутин с delay. Вам может потребоваться явно вызвать advanceUntilIdle() или advanceTimeBy(...).
  4. Всегда явно задавайте TestDispatcher в коде, который тестируете (через параметры или DI), чтобы избежать неявного использования Dispatchers.Main или других реальных диспетчеров.

Итог: runBlocking — инструмент для синхронного запуска в продакшене, runTest — специализированный и эффективный инструмент для написания быстрых и предсказуемых unit-тестов для асинхронного кода на корутинах, а runBlockingTest — его устаревший предшественник, от которого следует отказаться.

В чем разница между runBlockingTest, runTest и runBlocking? | PrepBro