¿Cómo probar los corutinas View Model que bloquean el hilo antes de las aserciones?
Estoy tratando de escribir una prueba para un Modelo de Vista. Estoy haciendo una prueba con instrumentación ya que necesito el “contexto”.
El modelo de vista y la prueba se ven así:
class MyViewModel(
private val dispatcher: CoroutineDispatchers = Dispatchers.IO) : ViewModel() {
private val _livedata = MutableLiveData<boolean>()
val livedata: LiveData<boolean> = _livedata
fun doSomething() {
viewModelScope.launch(dispatcher) {
// función suspendida con retrofit
_livedata.value = true
}
}
}
class MyViewModelTest {
private lateinit var viewModel: MyViewModel
@get:Rule
var mainCoroutineRule = MainCoroutineRule()
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
@Before
fun setup() {
viewModel = MyViewModel(mainCoroutineRule.dispatcher)
}
@Test
fun testMyViewModel() {
mainCoroutineRule.runBlockingTest {
viewModel.doSomething()
mainCoroutineRule.dispatcher.advanceUntilIdle()
val result = viewModel.livedata.getOrAwaitValue()
assertThat(result).isTrue()
}
}
}
El problema está en cómo “result” es nulo debido a que “doSomething()” es llamado en otro hilo y se ejecuta de forma asincrónica.
¿Cómo puedo ejecutar mi prueba para que la función suspendida bloquee el hilo y mi afirmación capture el “result” después de que la función se haya terminado?
Estoy bastante confundido con la información que hay allá afuera.
Creo que no necesito “InstantTaskExecutorRule()” porque estoy haciendo una prueba con instrumentación.
Agregar esta regla no ayuda:
@ExperimentalCoroutinesApi
class MainCoroutineRule(val dispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()):
TestWatcher(),
TestCoroutineScope by TestCoroutineScope(dispatcher) {
override fun starting(description: Description?) {
super.starting(description)
Dispatchers.setMain(dispatcher)
}
override fun finished(description: Description?) {
super.finished(description)
cleanupTestCoroutines()
Dispatchers.resetMain()
}
}
¿Necesito inyectar un despachador de hilos de ejecución en mi modelo de vista que bloquee el hilo principal?
davy.ai
Para asegurarse de que la función de suspensión en su modelo de vista bloquee el hilo para que su afirmación capture el resultado después de que la función de suspensión haya terminado, puede reemplazar el despachador
IO
con unTestCoroutineDispatcher
en su modelo de vista.Para hacer esto, necesita modificar el constructor de su
MyViewModel
para tomar un parámetro deCoroutineDispatcher
con un valor predeterminado deDispatchers.IO
. Luego, en su configuración de prueba, puede pasar unTestCoroutineDispatcher
en lugar deDispatchers.IO
.Aquí hay una versión actualizada de su código:
Tenga en cuenta que establecer el despachador principal en
testDispatcher
es necesario para que LiveData funcione correctamente en las pruebas.Además, en la función
testMyViewModel
, estamos usandotestDispatcher.runBlockingTest
en lugar demainCoroutineRule.runBlockingTest
. Esto se debe a que ya no estamos usando reglas de corutinas principales, por lo que debemos usar directamente elTestCoroutineDispatcher
.Finalmente, en lugar de llamar a
mainCoroutineRule.dispatcher.advanceUntilIdle()
, estamos llamando atestDispatcher.advanceUntilIdle()
para avanzar en el tiempo en el despachador de prueba.¡Espero que esto ayude!