Pruebas basadas en propiedades en Kotlin: rompemos el código más rápido de lo que crees

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

Por qué las pruebas comunes mienten y tú les crees



Imagina: escribiste una función, la cubriste con tres pruebas unitarias. Marca verde. CI pasa. Producción — error. ¿Te suena?



El problema de las pruebas unitarias clásicas es que verifican ejemplos concretos. Tú mismo inventas los datos de entrada y también escribes el resultado esperado. Es como un examen donde el estudiante prepara sus propias preguntas. Tarde o temprano, pasarás por alto un caso límite: null, una lista vacía, un número negativo o una cadena con caracteres Unicode.



Aquí entra en escena el testing basado en propiedades (o property-based testing). En lugar de escribir: «si se pasa 5, debe devolver 25», formulas una propiedad: «para cualquier número entero, el cuadrado siempre es no negativo». Y el framework genera cientos de valores aleatorios y verifica esa propiedad.



En este artículo, analizaremos cómo usar pruebas basadas en propiedades en Kotlin con la biblioteca Kotest. Aprenderás a escribir pruebas robustas, encontrar errores en etapas tempranas y dejar de temerle a la refactorización. Esto no es solo teoría aburrida: escribiremos código real que puedes aplicar de inmediato en un proyecto.



¿Qué es el property-based testing y por qué Kotlin?



La idea no es nueva: la popularizó la biblioteca QuickCheck para Haskell en 1999. Pero solo ahora, con el crecimiento de la complejidad de los sistemas backend y los microservicios, el testing basado en propiedades se está convirtiendo en un must-have en el stack del desarrollador.



Kotlin es el lenguaje ideal para este enfoque. ¿Por qué?



  • Capacidades funcionales: lambdas, funciones de extensión, inmutabilidad — todo esto simplifica la escritura de propiedades limpias.
  • Kotest — un framework potente que soporta de serie pruebas basadas en propiedades, generadores y Shrinking (algoritmo de minimización del ejemplo fallido).
  • Compatibilidad con Java: puedes probar código heredado escrito en Java usando los mismos enfoques.


Vamos directo al grano. A continuación, un ejemplo que cambiará tu percepción sobre las pruebas.



Tu primera prueba basada en propiedades en 5 minutos



Supongamos que tenemos una función que verifica si una cadena es un palíndromo:



fun isPalindrome(s: String): Boolean {    val cleaned = s.filter { it.isLetterOrDigit() }.lowercase()    return cleaned == cleaned.reversed()}


Una prueba común se ve así:



@Testfun `test known palindromes`() {    assertTrue(isPalindrome("A man, a plan, a canal: Panama"))    assertTrue(isPalindrome("racecar"))    assertFalse(isPalindrome("hello"))}


Todo funciona. Pero, ¿qué pasa si los datos de entrada contienen espacios, dígitos o símbolos? ¿Y si la cadena está vacía? ¿Y si consiste solo de espacios?



Ahora escribamos una prueba basada en propiedades con Kotest:



import io.kotest.core.spec.style.StringSpecimport io.kotest.property.forAllimport io.kotest.property.arbitrary.string

class PalindromePropertyTest : StringSpec({ "Cualquier cadena que pase la limpieza debe ser un palíndromo de sí misma" { forAll<String> { original -> val cleaned = original.filter { it.isLetterOrDigit() }.lowercase() isPalindrome(cleaned) == true } }})


¿Qué está pasando aquí? forAll<String> genera cadenas aleatorias: vacías, con espacios, con Unicode, con dígitos. Y para cada una verifica la propiedad. Si al menos una cadena viola la afirmación, la prueba falla y Kotest muestra el ejemplo mínimo que la reproduce.



Ya en esta etapa, puedes encontrar errores. Por ejemplo, si la cadena consiste solo de espacios — filter devolverá una cadena vacía, y isPalindrome("") devolverá true. Una prueba común habría pasado esto por alto.



Generadores: tu

Blogs

Book Recommendations