Pruebas unitarias confiables

Cuando una prueba unitaria falla debe ser una indicación clara de que alguien cambió algo en el código fuente y produjo un defecto en el funcionamiento de nuestra aplicación. Es decir, no queremos nunca que una prueba nos dé un “falso” positivo, donde una prueba en rojo no signifique nada. Eso hace que el equipo de desarrollo deje de ponerles atención y perdemos cualquier beneficio de la técnica.

En este artículo veremos cómo lograr pruebas confiables.

Recordemos que una prueba automatizada es unitaria si cumple estas características:

  1. Funciona en memoria: No accede a archivos, a bases de datos, a webservices u otra infraestructura.
  2. Es repetible: Funciona con un clic pues no requiere configuraciones manuales, no depende de la fecha actual o de alguna función aleatoria. Son determinísticas.

Además de lo anterior, una prueba unitaria debería ser confiable para que nos ayude en nuestros desarrollos. Cuando no lo es, escuchamos frases como las siguientes:

  • “La prueba falló porque tiene un defecto en su lógica. No es un defecto del software que prueba.”
  • “Corra las pruebas en este otro orden para que corran bien.”
  • “Esa prueba puede fallar por muchos motivos, tendremos que estudiar qué sucedió.”
  • “Las pruebas pasan pero realmente no prueban nada”

Las siguientes son tres indicaciones de que una prueba unitaria es confiable:

  1. No contienen lógica
  2. Son independientes
  3. Realizan una comparación (pero solo una)

1.No contienen lógica

Las pruebas unitarias no realizan ningún cálculo matemático, operación ni tienen ninguna estructura de control. Es decir, no encontraremos ningún if, switch, while, for o try.
De esta manera, reducirmos la probabilidad de que las pruebas contengan defectos y son más sencillas de entender. Una prueba unitaria siempre se lee tan sencilla como esto:

no-tienen-logica

2. Son independientes

Las pruebas deben poderse ejecutar en cualquier orden y no dependen de resultados de otras pruebas. Para lograrlo, no utilizamos variables globales, ni ningún pase de datos del resultado de una prueba hacia otra. Por esto, es bueno utilizar el patrón de elResultadoEsperado, elResultadoObtenido y una Comparación.

Cuando tenemos varias clases de pruebas unitarias que usan los mismos datos como su resultado esperado o como sus parámetros, estos los podemos colocar en una clase de “Escenarios”. Estos escenarios son de lectura solamente, nunca de escritura, con lo que aseguramos la independencias de las pruebas.

Por ejemplo, en esta clase de pruebas, cada prueba unitaria es muy sencilla porque los parámetros son inicializados en una clase de “Escenarios”:

son-independientes-con-escenarios

El código completo está en este repositorio: https://github.com/oscarcenteno/algoritmos.cs.garantias.

3. Realizan una comparación (pero solo una)

Una buena prueba verifica un resultado esperado contra uno obtenido (actual vs expected). Recordemos que esto requiere que el algoritmo sea observable.

Partiendo de esto, una prueba unitaria debe tener un solo motivo para fallar. Es decir, realiza una sola comparación. De esta manera, cuando falle sabremos rápidamente qué sucede y podremos corregirlo con confianza. Si la prueba tiene múltiples Asserts, cuando uno de ellos falle, no sabremos qué sucedió con los siguientes, y seremos más lentos para mantener todo el software.

Ahora, voy a mencionar que hay tipos de algoritmos. En un futuro artículo veremos ejemplos de cada uno. Lo importante de saber que hay diferentes tipos es porque cada uno de ellos se prueba con una estrategia de comparación específica.

  1. Un algoritmo que retorna un dato (número, texto, booleano, fecha)
  2. Un algoritmo que retorna una lista de datos
  3. Un algoritmo que retorna una estructura de datos (una clase con propiedades)
  4. Un algoritmo que retorna una lista de estructuras de datos

Por ahora, la noción principal que deseo que tengamos es que una prueba unitaria finaliza con una comparación (y solo una).

En resumen, una buena prueba unitaria es aquella que no tiene lógica alguna, es independiente y realiza una sola comparación. Esto lo podemos lograr si el algoritmo que probamos es observable y aislado.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

w

Conectando a %s