Pruebas en Kotlin: unit, integration, e2e de la A a la Z

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

Pruebas en Kotlin: unit, integration, e2e de la A a la Z

\n\n

El desarrollo moderno en Kotlin requiere un enfoque sistemático para las pruebas. Independientemente de si escribes un backend con Ktor o una aplicación móvil para Android, una cobertura de código de calidad con pruebas es la clave para la estabilidad y previsibilidad del proyecto. En este artículo, analizaremos tres niveles de pruebas: unitarias (unit), de integración (integration) y de extremo a extremo (e2e). Aprenderás qué herramientas usar, cómo escribir pruebas efectivas en Kotlin y evitar errores típicos.

\n\n

1. Pruebas unitarias en Kotlin: la base fundamental

\n\n

Las pruebas unitarias verifican el funcionamiento de funciones, clases o métodos individuales de forma aislada de las dependencias externas. En Kotlin, para esto se utiliza principalmente el framework JUnit 5 junto con la biblioteca de mocks MockK.

\n\n

Configuración del proyecto

\n\n

Añade las dependencias en build.gradle.kts:

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

Ejemplo de prueba unitaria

\n\n

Supongamos que tenemos un servicio simple para calcular un descuento:

\n\n
class DiscountService {\n    fun applyDiscount(price: Double, discountPercent: Int): Double {\n        require(discountPercent in 0..100) { "El porcentaje de descuento debe estar entre 0 y 100" }\n        return price * (100 - discountPercent) / 100\n    }\n}\n
\n\n

Prueba para este servicio:

\n\n
import org.junit.jupiter.api.Assertions.*\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.assertThrows\n\nclass DiscountServiceTest {\n\n    private val service = DiscountService()\n\n    @Test\n    fun `applyDiscount calcula correctamente un descuento del 50 por ciento`() {\n        val result = service.applyDiscount(1000.0, 50)\n        assertEquals(500.0, result, 0.001)\n    }\n\n    @Test\n    fun `applyDiscount lanza una excepción cuando el porcentaje es inválido`() {\n        assertThrows<IllegalArgumentException> {\n            service.applyDiscount(100.0, 150)\n        }\n    }\n}\n
\n\n

Consejo: Usa assertThrows para verificar excepciones y nombra las pruebas con cadenas claras; esto mejora la legibilidad de los informes.

\n\n

Mocking con MockK

\n\n

Cuando tu clase depende de otros componentes (por ejemplo, un repositorio o una API), usa mocks:

\n\n
class OrderService(private val paymentGateway: PaymentGateway) {\n    fun processOrder(amount: Double): String {\n        if (paymentGateway.charge(amount)) {\n            return "Pago exitoso"\n        }\n        return "Error de pago"\n    }\n}\n\n// Test\n@Test\nfun `processOrder devuelve éxito cuando el pago es exitoso`() {\n    val mockGateway = mockk<PaymentGateway>()\n    every { mockGateway.charge(any()) } returns true\n\n    val service = OrderService(mockGateway)\n    val result = service.processOrder(500.0)\n\n    assertEquals("Pago exitoso", result)\n    verify { mockGateway.charge(500.0) }\n}\n
\n\n

2. Pruebas de integración: verificación de la interacción entre componentes

\n\n

Las pruebas de integración verifican cómo diferentes partes del sistema funcionan juntas: base de datos, APIs externas, sistema de archivos. Para Kotlin, Testcontainers es ideal: una biblioteca para levantar contenedores Docker durante las pruebas.

\n\n

Ejemplo con base de datos PostgreSQL

\n\n

Añade las dependencias:

\n\n
testImplementation("org.testcontainers:testcontainers:1.19.3")\ntestImplementation("org.testcontainers:postgresql:1.19.3")\n
\n\n

Escribamos una prueba para la capa DAO:

\n\n
class UserRepositoryIntegrationTest {\n\n    companion object {\n        private val postgres = PostgreSQLContainer<Nothing>("postgres:15").apply {\n            withDatabaseName("testdb")\n            withUsername("test")\n            withPassword("test")\n            start()\n                

Blogs

Book Recommendations