Skip to main content

Prueba basada en propiedades con ScalaTest: Obtener el máximo de una lista

⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.


r8vnhill/scala-dibs

Cuando implementamos una función para obtener el máximo de una lista, es crucial asegurarnos de que su comportamiento sea correcto para una variedad de entradas. En lugar de escribir casos de prueba individuales, podemos utilizar Property-Based Testing (PBT) para verificar automáticamente propiedades generales de la función en múltiples escenarios generados aleatoriamente.

En este ejemplo, validaremos la función biggest con ScalaTest y ScalaCheck, asegurándonos de que siempre retorne el elemento correcto sin depender de casos de prueba manuales. Esto nos permite descubrir errores sutiles y asegurar la robustez del código.

🧪 Test en ScalaTest

Veamos un ejemplo similar al que vimos con Kotest: encontrar el máximo de una lista de enteros. En ScalaTest, usaremos el módulo ScalaCheck para generar propiedades y verificar el comportamiento de la función bajo prueba.

forAll(Gen.listOf(Gen.choose(0, 100))) { list =>
whenever(list.nonEmpty) {
biggest(list) shouldBe list.sorted.last
}
}
¿Qué acabamos de hacer?
  • Gen.listOf(Gen.choose(Int.MinValue, Int.MaxValue)): Genera listas de enteros aleatorios entre los valores mínimos y máximos posibles en Scala.
  • whenever(list.nonEmpty): Asegura que la propiedad solo se aplique a listas no vacías, evitando que el test falle por una lista vacía.
  • forAll: Itera sobre todos los valores generados por el generador de listas y aplica la propiedad a cada uno.
  • biggest(list): Es la función que estamos probando, la cual debe devolver el último elemento de la lista ordenada.

📊 Resumen comparativo

CaracterísticaScalaTestKotest
Uso de propiedades (PBT)Usa ScalaCheck para pruebas basadas en propiedades, lo que requiere un módulo adicional.Tiene soporte nativo para Property-Based Testing sin dependencias adicionales.
Generadores de datosSe usan los generadores de ScalaCheck, como Gen.listOf para listas, lo que ofrece flexibilidad.Usa Arb para generar datos, con integración directa y más personalización.
Condiciones previasSe usa whenever para aplicar propiedades solo cuando se cumplen ciertas condiciones, como listas no vacías.Genera datos que cumplen con las condiciones necesarias desde el principio, evitando verificaciones adicionales.
Interfaz de usoRequiere la integración de ScalaCheckPropertyChecks para escribir propiedades con forAll.Usa checkAll directamente, con una interfaz más simplificada y fluida para propiedades.
IntegraciónDepende de la integración con ScalaCheck para PBT.Tiene una integración más directa y simplificada para PBT sin necesidad de módulos externos.

⚖️ Beneficios y limitaciones

Beneficios

  • Flexibilidad en el uso de generadores: ScalaTest, mediante ScalaCheck, proporciona una amplia gama de generadores que permiten una gran personalización, útil en escenarios complejos.
  • Compatibilidad con otros frameworks: ScalaTest se integra bien con diversas bibliotecas y frameworks como Akka, Play, y Spark, lo que lo convierte en una opción versátil en proyectos Scala.
  • Condiciones previas: El uso de whenever permite aplicar propiedades únicamente cuando se cumplen condiciones específicas, proporcionando más control sobre la ejecución de los tests.

Limitaciones

  • Dependencia de módulos adicionales: ScalaTest requiere la integración de ScalaCheck para pruebas basadas en propiedades, lo que introduce una dependencia adicional que puede aumentar la complejidad del proyecto.
  • Menos integración directa: A diferencia de Kotest, ScalaTest no tiene soporte nativo para Property-Based Testing, lo que hace que el flujo de trabajo sea menos fluido al depender de ScalaCheck.
  • Verificación manual de condiciones: Es necesario agregar verificaciones manuales como whenever para asegurarse de que las condiciones previas se cumplan, mientras que en Kotest, esto se maneja automáticamente generando los datos adecuados.

📌 Conclusiones

En esta lección, exploramos cómo utilizar ScalaTest y ScalaCheck para implementar pruebas basadas en propiedades (Property-Based Testing, PBT) con el objetivo de validar la función biggest. A través de este enfoque, pudimos comprobar su correcto funcionamiento en un amplio rango de casos generados automáticamente, evitando depender únicamente de pruebas manuales o casos específicos.

🔑 Puntos clave

  1. PBT como herramienta de validación robusta: En lugar de depender de pruebas manuales con casos limitados, el uso de generadores aleatorios permitió verificar el comportamiento de biggest en múltiples escenarios de forma automatizada.
  2. Diferencias entre ScalaTest y Kotest: Mientras que ScalaTest requiere la integración con ScalaCheck para PBT, Kotest ofrece soporte nativo, facilitando su uso sin dependencias externas.
  3. Manejo de condiciones previas: ScalaTest requiere el uso de whenever para evitar listas vacías en las pruebas, mientras que en Kotest se pueden definir restricciones directamente en los generadores.
  4. Flexibilidad vs. Simplicidad: ScalaCheck proporciona una gran personalización en la generación de datos, pero Kotest tiene una interfaz más simple e integrada para realizar pruebas basadas en propiedades.

✅ Reflexión final

El uso de Property-Based Testing nos permite escribir pruebas más generales y evitar errores sutiles en funciones críticas como biggest. Aunque ScalaTest con ScalaCheck ofrece flexibilidad, la necesidad de configuraciones adicionales puede hacer que la experiencia sea más compleja en comparación con Kotest. La elección entre estos frameworks dependerá de las necesidades del proyecto y la familiaridad con cada herramienta.

Implementar PBT en proyectos de prueba ayuda a mejorar la calidad y confiabilidad del software, especialmente en funciones donde es difícil prever todos los casos posibles manualmente.