Lukasz Kalnik
02/03/2022, 2:56 PM@Test
fun `when no gateway from scanning present then throw`() {
every { state.gateway } returns null
assertThatIllegalStateException().isThrownBy { runBlocking { useCase.execute(Params()) } }
}
This is what it looks like after the migration, according to the official migration guide:
val exceptions = mutableListOf<Throwable>()
val customCaptor = CoroutineExceptionHandler { _, throwable ->
exceptions.add(throwable)
}
@Test
fun `when no gateway from scanning present then throw`() = runTest {
every { state.gateway } returns null
launch(customCaptor) {
useCase.execute(Params())
}
advanceUntilIdle()
assertThat(exceptions).hasSize(1)
.first().isInstanceOf(IllegalStateException::class.java)
}
However, the exception is for some reason not caught by the customCaptor
, but thrown in the test and the test fails.Lukasz Kalnik
02/03/2022, 3:03 PMrunBlocking
by runTest
, but this is not recommended according to the migration guide (it could obscure other problems with the test detected by the runTest
cleanup procedure).Lukasz Kalnik
02/03/2022, 3:06 PMuseCase
under test. Should I inject one and replace it with the TestScope.coroutineContext
for testing?Lukasz Kalnik
02/03/2022, 3:20 PM@BeforeTest
fun setUp() {
Dispatchers.setMain(StandardTestDispatcher())
}
Dmitry Khalanskiy [JB]
02/04/2022, 8:13 AMassertFailsWith<IllegalStateException> { useCase.execute(Params()) }
(without `launch`ing a new coroutine) work?
The reason the whole test fails with an exception is that the coroutine you launch fails with that exception. The uncaught exception handler is not used, because, well, the exception is not uncaught, it's propagated using structured concurrency.Lukasz Kalnik
02/04/2022, 8:43 AMLukasz Kalnik
02/04/2022, 8:44 AMLukasz Kalnik
02/04/2022, 8:45 AMuncaughtExceptions
when the uncaught exceptions are actually expected. In this case, cleanupTestCoroutines
will fail with an exception that is being caught later. It would be better in this case to use a custom CoroutineExceptionHandler
so that actual problems that could be found by the cleanup procedure are not superseded by the exceptions that are expected. An example is shown below."Dmitry Khalanskiy [JB]
02/04/2022, 8:45 AMLukasz Kalnik
02/04/2022, 8:46 AMLukasz Kalnik
02/04/2022, 8:46 AMDmitry Khalanskiy [JB]
02/04/2022, 8:47 AMDmitry Khalanskiy [JB]
02/04/2022, 8:48 AMlaunch(SupervisorJob()) {
launch {
throw IllegalStateException()
}
}
Lukasz Kalnik
02/04/2022, 8:48 AMDmitry Khalanskiy [JB]
02/04/2022, 8:49 AMSupervisorJob
don't have the right to fail the SupervisorJob
, so they can't propagate the exception upwards, so they have to resort to uncaught exception handlers.Lukasz Kalnik
02/04/2022, 8:49 AMLukasz Kalnik
02/04/2022, 8:51 AMDmitry Khalanskiy [JB]
02/04/2022, 9:18 AMLukasz Kalnik
02/04/2022, 9:37 AM