Antes de empezar a decirles las técnicas de diseño de casos de prueba, me gustaría empezar explicándoles que es un Caso de Prueba
, solo para que no haya confusiones y puedan entender el tema de una manera mas clara, concisa, precisa y armónica.
¿De qué hablamos cuando nos referimos a un Caso de Prueba? Veamos algunas definiciones:
De acuerdo al Estándar IEEE 610 (1990) un caso de prueba se define como:
"Un conjunto de entradas de prueba, condiciones de ejecución, y resultados esperados desarrollados con un objetivo particular, tal como el de ejercitar
un camino en particular de un programa o el verificar que cumple con un requerimiento específico.”
Brian Marick utiliza un término relacionado para describir un caso de prueba que está ligeramente documentado, referido como “La Idea de Prueba”:
“Una idea de prueba es una breve declaración de algo que debería ser probado. Por ejemplo, si se está probando la función de la raíz cuadrada,
una idea de prueba sería el ‘probar un número que sea menor que cero’. La idea es chequear si el código maneja un caso de error.”
Ahora si vamos a empezar con lo bueno, una vez que ya sabemos que es el caso de prueba. Existen distintas técnicas de diseño de casos de prueba, que permiten seleccionar la menor cantidad de casos con mayor probabilidad de encontrar fallas en el sistema. Por este motivo, estos casos se consideran los más interesantes para ejecutar, ya que el testing exhaustivo no solo es imposible de ejecutar en un tiempo acotado, sino que también es muy caro e ineficiente. Es así que se vuelve necesario seleccionar de una forma inteligente los valores de entrada que tengan más posibilidades de descubrir un error. Para esto, el diseño de pruebas se basa en técnicas bien conocidas y utilizadas, tales como particiones de equivalencia, valores límites, combinaciones por pares, tablas de decisión o máquinas de estado. Por ejemplo probar valores límites, basado en que hay siempre probabilidad de que no se estén controlando estas situaciones por errores al programar y utilizar un “menor” en lugar de un “menor igual”, etc. También existen técnicas más avanzadas como la que implica el uso de máquinas de estado, etc.
La clasificación más importante y más difundida de técnicas de diseño de casos de prueba es basada en la información utilizada como entrada. Si utilizamos información interna del sistema que estamos probando, tal como el código, esquema de base de datos, etc., entonces se dice que estamos siguiendo una estrategia de caja blanca. Si en cambio nos basamos únicamente en la observación de entradas y salidas del sistema, estamos siguiendo un enfoque de caja negra. Efectivamente, ese caso sería como considerar que el sistema es una caja a la cual no podemos mirar su interior. Por esta asimilación es también que a las técnicas de caja blanca a veces se les dice técnicas de “caja transparente”, haciendo mejor referencia a que la idea es poder mirar qué hay dentro de esa caja que estamos probando.
**
Podríamos decir que con caja blanca nos preocupamos por lo que pasa dentro de la caja y con caja negra nos preocupamos por lo que pasa fuera de ella. Muchas veces el límite no está claro, o tal vez estamos siguiendo un enfoque de caja negra, pero como sabemos algo de lo que sucede dentro entonces aprovechamos esa información. También hay quienes hablan de “caja gris” cuando se combinan ambos enfoques.
**
Lo importante es que puede haber una diferencia en el alcance, la forma de hacernos las preguntas, la información y los objetivos de las pruebas que diseñemos.
Este tipo de clasificación también es muy difundida, y particularmente útil. Más que nada porque nos habla de la especificidad con la que está detallado el caso de prueba.
**
Un caso de prueba abstracto se caracteriza por no tener determinados los valores para las entradas y salidas esperadas. Se utilizan variables y se describen con operadores lógicos ciertas propiedades que deben cumplir (por ejemplo, “edad > 18” o “nombre válido”). Entonces, la entrada concreta no está determinada.
**
Un caso de prueba específico (o concreto) es una instancia de un caso de prueba abstracto, en la que se determinan valores específicos para cada variable de entrada y para cada salida esperada.
**
Cada caso de prueba abstracto puede ser instanciado con distintos valores, por lo que tendrá, al momento de ser ejecutado (o diseñado a bajo nivel) un conjunto de casos de prueba específicos, donde se asigna un valor concreto a cada variable (tanto de entrada como de salida) de acuerdo a las propiedades y restricciones lógicas que tiene determinadas.
La clasificación anterior nos da pie para hablar de una técnica de testing que es muy útil, y que puede que la nombremos en varias situaciones: pruebas dirigidas por datos, o del inglés bien conocido como Data-Driven Testing.
**
Esta es una técnica para construir casos de prueba basándose en los datos entrada, y separando el flujo que se toma en la aplicación. O sea, por un lado se representa el flujo (la serie de pasos para ejecutar el caso de prueba) y por otro lado se almacenan los datos de entrada y salida esperados. Esto permite agregar nuevos casos de prueba fácilmente, ingresando simplemente nuevos datos de entrada y de salida esperados, que sirvan para ejecutar el mismo flujo.
**
Por ejemplo y para que quede más claro, se podría automatizar el “login” de un sistema web. Por un lado definiríamos el flujo del caso de prueba, el cual nos indica que tenemos que ir a la URL de la aplicación, luego ingresar un nombre de usuario, un password, y dar OK, y nos aparecería un mensaje que diga “Bienvenido”. Por otro lado tendríamos una fuente de datos en donde especificaríamos distintas combinaciones de nombres de usuario y password, y mensaje de respuesta esperado. El día de hoy se me ocurre poner un usuario válido, password válido y mensaje de bienvenida; mañana agrego otro que valida que ante un password inválido me da un mensaje de error correspondiente, y esto lo hago simplemente agregando una línea de datos, sin necesidad de definir otro caso de prueba distinto.
**
Entonces, el flujo de la aplicación se está definiendo con casos de prueba abstractos, que al momento de ser ejecutados con un juego específico de datos, se estarían convirtiendo en casos de prueba específicos. De ahí el vínculo entre data-driven testing y las definiciones de casos de prueba abstracto y específico.