MockWebServer
Clase 11 de 16 • Curso de Android Testing
Resumen
La integración de pruebas de red en el desarrollo de aplicaciones móviles es fundamental para garantizar la robustez de nuestros sistemas. Cuando trabajamos con datos que provienen de peticiones HTTP, necesitamos asegurarnos de que nuestra aplicación responda correctamente tanto en escenarios exitosos como en situaciones de error. En este artículo, exploraremos cómo implementar pruebas controladas de escenarios de red utilizando MockWebServer, una herramienta poderosa que nos permite simular respuestas de servidores sin necesidad de conexiones reales a Internet.
¿Qué es MockWebServer y por qué utilizarlo?
MockWebServer es una biblioteca que nos permite simular un servidor web para nuestras pruebas, proporcionando respuestas predefinidas a las solicitudes HTTP que realiza nuestra aplicación. Esta herramienta es esencial para probar el comportamiento de nuestros repositorios y lógica de negocio frente a diferentes respuestas de red, sin depender de conexiones a Internet o servidores reales.
Las ventajas de utilizar MockWebServer incluyen:
- Control total sobre las respuestas del servidor
- Capacidad para simular diferentes códigos de estado HTTP
- Posibilidad de probar escenarios de error de manera controlada
- Independencia de servicios externos durante las pruebas
¿Cómo configurar MockWebServer en nuestros tests?
Para implementar MockWebServer en nuestras pruebas, necesitamos seguir varios pasos clave:
- Declarar las variables necesarias para nuestro test
- Configurar el servidor mock en el método de configuración
- Definir las respuestas que queremos simular
- Liberar los recursos después de las pruebas
Veamos cómo implementar esto en código:
private lateinit var mockWebServer: MockWebServer
private lateinit var mockApi: UserApi
@Before
fun setUp() {
// Inicializar el MockWebServer
val contentType = "application/json".toMediaType()
mockWebServer = MockWebServer()
// Configurar Retrofit para usar el MockWebServer
mockApi = Retrofit.Builder()
.baseUrl(mockWebServer.url("/"))
.addConverterFactory(Json.asConverterFactory(contentType))
.build()
.create(UserApi::class.java)
}
@After
fun tearDown() {
// Liberar recursos
mockWebServer.shutdown()
}
En este código, estamos configurando un servidor mock que responderá a las solicitudes HTTP con el tipo de contenido JSON. Luego, configuramos Retrofit para usar este servidor mock como su URL base.
¿Cómo simular respuestas exitosas con MockWebServer?
Una vez configurado nuestro MockWebServer, podemos comenzar a simular diferentes respuestas. Para probar escenarios exitosos, necesitamos enqueue respuestas con código 200 y cuerpos JSON que representen los datos esperados.
Veamos un ejemplo completo de un test que verifica el comportamiento de un repositorio cuando recibe respuestas exitosas:
@Test
fun givenValidUserId_whenGetProfile_withMockWebServer_thenReturnsProfile() = runTest {
// Given
val user = User(
id = 1,
userName = "testUser",
places = listOf(
Place(
id = 1,
name = "testPlace1",
coordinates = Coordinates(
latitude = 1.0,
longitude = 1.0
)
),
Place(
id = 2,
name = "testPlace2",
coordinates = Coordinates(
latitude = 2.0,
longitude = 2.0
)
)
)
)
// Simular respuesta para el perfil
mockWebServer.enqueue(
MockResponse()
.setResponseCode(200)
.setBody("""
{
"id": 1,
"userName": "testUser"
}
""".trimIndent())
)
// Simular respuesta para los lugares
mockWebServer.enqueue(
MockResponse()
.setResponseCode(200)
.setBody("""
[
{
"id": 1,
"name": "testPlace1",
"coordinates": {
"latitude": 1,
"longitude": 1
}
},
{
"id": 2,
"name": "testPlace2",
"coordinates": {
"latitude": 2,
"longitude": 2
}
}
]
""".trimIndent())
)
// When
val repository = UserRepositoryImplementation(mockApi)
val result = repository.getProfile(1)
// Then
assertThat(result.isSuccess).isTrue()
assertThat(result.getOrThrow()).isEqualTo(user)
}
En este test:
- Definimos los datos esperados (un usuario con sus lugares)
- Encolamos dos respuestas en el MockWebServer: una para el perfil y otra para los lugares
- Ejecutamos la acción que queremos probar (obtener el perfil)
- Verificamos que el resultado sea exitoso y contenga los datos esperados
¿Qué ocurre si falta una respuesta?
Es importante entender que MockWebServer responde a las solicitudes en el orden en que se encolan las respuestas. Si nuestra lógica realiza más solicitudes de las que hemos encolado, el test podría quedarse esperando indefinidamente o fallar con un timeout.
Por ejemplo, si eliminamos una de las respuestas encoladas en nuestro ejemplo anterior, el test podría quedarse esperando la respuesta que nunca llegará, lo que resultaría en un timeout.
¿Cómo simular errores HTTP con MockWebServer?
Probar escenarios de error es tan importante como probar escenarios exitosos. Con MockWebServer, podemos simular fácilmente diferentes códigos de error HTTP para verificar cómo responde nuestra aplicación.
@Test
fun givenInvalidUserId_whenGetProfile_returnsError() = runTest {
// Simular respuesta de error para el perfil
mockWebServer.enqueue(
MockResponse()
.setResponseCode(404)
.setBody("{}")
)
// Simular respuesta de error para los lugares
mockWebServer.enqueue(
MockResponse()
.setResponseCode(404)
.setBody("{}")
)
// When
val repository = UserRepositoryImplementation(mockApi)
val result = repository.getProfile(999) // ID inválido
// Then
assertThat(result.isFailure).isTrue()
assertThat(result.exceptionOrNull()).isInstanceOf(HttpException::class.java)
}
En este test:
- Encolamos respuestas con código de error 404
- Ejecutamos la acción con un ID inválido
- Verificamos que el resultado sea un fallo y que la excepción sea del tipo esperado (HttpException)
Este enfoque nos permite verificar que nuestro repositorio maneja correctamente los errores HTTP y los propaga adecuadamente a las capas superiores de la aplicación.
La implementación de pruebas con MockWebServer nos permite validar el comportamiento de nuestra aplicación frente a diferentes escenarios de red de manera controlada y reproducible. Esto aumenta la confiabilidad de nuestro código y nos ayuda a detectar problemas antes de que lleguen a producción. ¿Has implementado pruebas de red en tus proyectos? Comparte tus experiencias y desafíos en los comentarios.