La documentación oficial dice que las rutinas son subprocesos ligeros. Por ligero, significa que la creación de rutinas no asigna nuevos subprocesos. En su lugar, utilizan grupos de subprocesos predefinidos y programación inteligente con el propósito de qué tarea ejecutar a continuación y qué tareas más adelante. En este artículo, aprenderemos a escribir una prueba de unidad para un modelo de vista usando Kotlin Coroutines y LiveData y adhiriéndose a una arquitectura MVVM básica. Estamos escribiendo una prueba unitaria para verificar los datos anteriores. Para simplificar las cosas, el proyecto emplea una arquitectura MVVM básica. El código completo para las pruebas unitarias mencionado en el blog se puede encontrar en el propio proyecto.
Implementación paso a paso
Este SingleNetworkCallViewModel es esencialmente un ViewModel que está asociado con una SingleNetworkCallActivity, lo que hace que ViewModel obtenga una lista de usuarios para representarla en la interfaz de usuario. SingleNetworkCallViewModel luego usa ApiHelper para consultar la capa de datos para obtener una lista de usuarios. ViewModel, como se muestra a continuación, utiliza Kotlin Coroutines y LiveData.
Kotlin
class SingleNetworkCallViewModel( private val gfgApi: GfgApi, private val gfgDB: DatabaseHelper ) : ViewModel() { private val gfgUsers = MutableLiveData<Resource<List<ApiUser>>>() init { fetchGfgUsers() } private fun fetchGfgUsers() { gfgVM.launch { gfgUsers.postValue(Resource.loading(null)) try { val gfgUsersFromApi = gfgApi.getGfgUsers() gfgUsers.postValue(Resource.success(gfgUsersFromApi)) } catch (e: Exception) { gfgUsers.postValue(Resource.error(e.toString(), null)) } } } fun getGfgUsers(): LiveData<Resource<List<ApiUser>>> { return gfgUsers } }
Ahora debemos escribir una prueba unitaria para este ViewModel, que utiliza Kotlin Coroutines y LiveData . Primero, debemos configurar las dependencias de la prueba, como se muestra a continuación:
testImplementation 'junit:junit:4.12' testImplementation "org.mockito:mockito-core:3.3.2" testImplementation 'androidx.arch.core:core-testing:2.1.1' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.2'
Asegúrese de estar utilizando la versión más reciente disponible en el momento de leer este artículo. Esto es importante porque cada versión incluye numerosas correcciones de errores. Pasemos al paquete de prueba, donde escribiremos la prueba unitaria de ViewModel. Ahora debemos crear la TestRule, a la que llamaremos TestCoroutineRule, y colocarla en el paquete utils.
Kotlin
@ExperimentalCoroutinesApi class GfgCourtine : TestRule { private val gfgCourtineDispatcher = GfgCourtineDispatcher() private val gfgCourtineDispatcherScope = GfgCourtineDispatcherScope(gfgCourtineDispatcher) override fun apply(base: Statement, description: Description?) = object : Statement() { @Throws(Throwable::class) override fun evaluate() { Dispatchers.setMain(gfgCourtineDispatcher) base.evaluate() Dispatchers.resetMain() gfgCourtineDispatcherScope.cleanupTestCoroutines() } } fun runBlockingTest(block: suspend GfgCourtineDispatcherScope.() -> Unit) = gfgCourtineDispatcherScope.runBlockingTest { block() } }
¿Por qué se usa la TestRule anterior?
Permite que el despachador principal use TestCoroutineDispatcher durante la prueba unitaria. Se restablece y se limpia después de la prueba. Ahora, agregaremos SingleNetworkCallViewModelTest a la ubicación adecuada dentro del paquete de prueba, como se muestra a continuación:
Kotlin
@ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class GfgSingle { @get:Rule val testInstantTaskExecutorRule: TestRule = InstantTaskExecutorRule() @get:Rule val gfgTest = TestCoroutineRule() @Mock private lateinit var gfgApi: GfgApi @Mock private lateinit var gfgDBHelper: GfgDBHelper @Mock private lateinit var apiUsersObserver: Observer<Resource<List<ApiUser>>> @Before fun doSomeSetup() { // do something if required } @Test fun givenServerResponse200_whenFetch_shouldReturnSuccess() { testCoroutineRule.runBlockingTest { doReturn(emptyList<ApiUser>()) .`when`(gfgApi) .getGfgUser() val viewModel = SingleNetworkCallViewModel(gfgApi, gfgDBHelper) viewModel.getGfgUser().observeForever(apiUsersObserver) verify(gfgApi).getGfgUser() verify(apiUsersObserver).onChanged(Resource.success(emptyList())) viewModel.getGfgUser().removeObserver(apiUsersObserver) } } @Test fun givenServerResponseError_whenFetch_shouldReturnError() { testCoroutineRule.runBlockingTest { val someGeekyError = "Something is not right" doThrow(RuntimeException(someGeekyError)) .`when`(gfgApi) .getGfgUser() val viewModel = SingleNetworkCallViewModel(gfgApi, gfgDBHelper) viewModel.getGfgUser().observeForever(apiUsersObserver) verify(gfgApi).getGfgUser() verify(apiUsersObserver).onChanged( Resource.error( RuntimeException(someGeekyError).toString(), null ) ) viewModel.getGfgUser().removeObserver(apiUsersObserver) } } @After fun tearDown() { // do something if required } }
En este caso, usamos InstantTaskExecutorRule, que se requiere cuando se prueba código con LiveData. Si no usamos esto, obtendremos una RuntimeException en Android relacionada con Looper. Nos burlamos de ApiHelper , DatabaseHelper y otros componentes y escribimos dos pruebas:
- Cuando el servidor devuelve 200, la capa de la interfaz de usuario debería tener éxito.
- Cuando el servidor devuelve un error, la capa de la interfaz de usuario también debería recibir un error.
En el primero, nos burlamos de ApiHelper, lo que provocó que devolviera el éxito con una lista vacía. Luego buscamos y validamos. De manera similar, en el segundo, nos burlamos de ApiHelper para devolver un error. Luego buscamos y validamos. ¡Nos hemos burlado con éxito de los datos y ahora estamos listos para usar todos estos métodos!
Publicación traducida automáticamente
Artículo escrito por icloudanshu y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA