Mocks y fixtures en Kotlin: guía de pruebas sin dolor

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué las pruebas sin mocks son como café sin cafeína?

\n\n

¡Hola, colega! Si escribes en Kotlin y quieres que tu código no se rompa en cada segundo commit, tarde o temprano llegarás a las pruebas. Y en las pruebas, a los objetos mock y fixtures. Sin ellos, las pruebas unitarias se convierten en pruebas de integración: no pruebas una sola clase, sino toda una cadena de dependencias. Y si la base de datos falla o la API devuelve un 500, la prueba fallará, aunque tu código pueda ser perfecto.

\n\n

En este artículo, analizaremos cómo usar correctamente objetos Mock y fixtures en pruebas de Kotlin para que las pruebas sean rápidas, confiables y te digan la verdad, no "todo está roto, arréglalo". ¡Allá vamos!

\n\n

¿Qué es un mock y para qué sirve en Kotlin?

\n\n

Un objeto Mock es una simulación de un objeto real. En lugar de levantar un servidor completo o una base de datos, creamos un "simulacro" que se comporta como le indiquemos. Esto permite aislar el código bajo prueba del mundo exterior.

\n\n

Conceptos principales

\n
    \n
  • Mock — un objeto cuyo comportamiento de métodos controlamos. Podemos definir qué devolverá y verificar si fue llamado.
  • \n
  • Stub — un caso particular de mock que solo devuelve valores predefinidos. No verifica llamadas.
  • \n
  • Fixture — un conjunto de datos o estados preparados previamente, necesarios para ejecutar la prueba. Por ejemplo, un usuario de prueba o configuraciones de BD.
  • \n
\n\n

En el mundo de Kotlin hay dos actores principales: MockK (nativo de Kotlin) y Mockito (popular en Java). Usaremos MockK, ya que se lleva mejor con corrutinas, funciones de extensión y clases selladas.

\n\n

Configuración del proyecto: agregando MockK y JUnit 5

\n\n

Para empezar, agreguemos las dependencias en build.gradle.kts:

\n\n
dependencies {\n    testImplementation("io.mockk:mockk:1.13.8")\n    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")\n}\n
\n\n

Ahora podemos escribir pruebas. Crearemos un servicio simple y lo probaremos usando mocks.

\n\n

Primer ejemplo: simulando un repositorio

\n\n

Imagina que tenemos un UserService que depende de UserRepository:

\n\n
class UserService(private val repository: UserRepository) {\n    fun getUserName(id: Long): String {\n        val user = repository.findById(id)\n            ?: throw IllegalArgumentException("User not found")\n        return user.name\n    }\n}\n
\n\n

Ahora escribamos una prueba usando un objeto mock para el repositorio:

\n\n
import io.mockk.every\nimport io.mockk.mockk\nimport io.mockk.verify\nimport org.junit.jupiter.api.Test\nimport kotlin.test.assertEquals\nimport kotlin.test.assertFailsWith\n\nclass UserServiceTest {\n\n    private val repository = mockk<UserRepository>()\n    private val service = UserService(repository)\n\n    @Test\n    fun `should return user name when user exists`() {\n        // Arrange\n        every { repository.findById(1L) } returns User(1L, "Alice")\n\n        // Act\n        val name = service.getUserName(1L)\n\n        // Assert\n        assertEquals("Alice", name)\n        verify { repository.findById(1L) }\n    }\n\n    @Test\n    fun `should throw exception when user not found`() {\n        // Arrange\n        every { repository.findById(any()) } returns null\n\n        // Act & Assert\n        assertFailsWith<IllegalArgumentException> {\n            service.getUserName(99L)\n        }\n    }\n}\n
\n\n

Observa: every define el comportamiento del mock, verify comprueba que el método fue llamado. Esta es la base de objetos Mock y fixtures en pruebas de Kotlin.

\n\n

Fixtures: preparando datos con antelación

\n\n

Cuando hay muchas pruebas, duplicar la creación de datos es una mala práctica. Aquí es donde entran las fixtures. En Kotlin, es conveniente

Blogs

Book Recommendations