Сравните ваш тест со следующим, в котором не используются сопрограммы, но вместо этого начинается новый поток:
@Test
fun why_does_this_test_pass() {
val job = thread { // <-- NOTE: Changed here
throw IllegalStateException("why does this exception not fail the test?")
}
// NOTE: No need for runBlocking any more
job.join() // ensures exception is thrown before test function completes
}
Что здесь происходит?Как и тест с launch
, этот тест проходит , если вы его запустите, но исключение будет напечатано на консоли.
Таким образом, использование launch
для запуска новой сопрограммы очень похоже на использование thread
для запуска нового потока.Если это не удается, ошибка обрабатывается необработанным обработчиком исключений в thread
и CoroutineExceptionHandler
(см. Его в документации) launch
.Исключения при запуске не проглатываются , а обрабатываются обработчиком исключений сопрограммы.
Если вы хотите, чтобы исключение распространялось на тест, вы должны заменить launch
с async
и замените join
на await
в вашем коде.См. Также этот вопрос: В чем разница между запуском / соединением и асинхронностью / ожиданием в сопрограммах Kotlin
ОБНОВЛЕНИЕ : сопрограммы Kotlin недавно представили концепцию "структурированногоПараллелизм », чтобы избежать потери такого рода исключений.Код в этом вопросе больше не компилируется.Чтобы скомпилировать его, вы должны либо явно сказать GlobalScope.launch
(как в «Я подтверждаю, что все нормально, чтобы потерять мои исключения, вот моя подпись»), либо заключить тест в runBlocking { ... }
, в этом случае исключение не являетсяпотерял.