Construir casos de prueba eficaces ayuda a que tu código funcione correctamente en diferentes escenarios. Permite detectar errores antes de hacer la entrega final de tu código. Ayuda a validar requisitos, mejora la comprensión del problema y fomenta el pensamiento crítico. También ayuda a evitar errores cuando haces cambios en tu código incluyendo o modificando funcionalidades existentes. Finalmente, simplifica el mantenimiento y aumenta la confianza en la calidad del software.
Qué es un caso de prueba
Un caso de prueba es un ejemplo concreto que usamos para verificar si una parte del código funciona correctamente. Cada caso de prueba debe incluir:
- una entrada: datos que damos al programa,
- un resultado esperado: lo que debería devolver
- el resultado real: lo que realmente devuelve al ejecutarlo.
Para que sea eficaz, un caso de prueba debe cumplir los siguientes requisitos:
- Claridad: Ser fácil de entender y describir qué está probando.
- Relevancia: Probar algo importante, como un requisito o posible error.
- Variedad: Considerar entradas normales, casos extremos y datos inesperados.
- Previsibilidad: Tener un resultado esperado claro y comprobable.
A continuación te muestro una guía sencilla y práctica sobre cómo puedes construir intuitivamente casos de prueba eficaces.
1. Entender los requisitos del problema
- Pregunta clave: ¿Qué se espera que haga el código?
- Divide los requisitos en casos específicos y explícitos. Por ejemplo, si una función debe verificar si un número es primo:
- Debe devolver
true
para números primos (2, 3, 5…). - Debe devolver
false
para números no primos (4, 6, 8…). - Debe manejar correctamente casos extremos como 0, 1 o números negativos.
- Debe devolver
2. Identificar tipos de entradas
Considera todos los distintos tipos de entradas para cubrir posibles escenarios:
- Entradas válidas comunes: Valores que cumplen las condiciones esperadas.
- Casos extremos o límites: Valores mínimos, máximos o límites cercanos. Por ejemplo, si el código maneja edades, probar con 0, 1, y el máximo permitido (e.g., 120).
- Entradas inválidas: Datos inesperados como
null
, cadenas vacías o números fuera del rango.
3. Comparar resultados esperados y reales
- Antes de ejecutar el código debes ser capaz de predecir el resultado esperado de cada caso.
- Compara la salida real con la esperada para identificar errores.
4. Usar una tabla para planificar pruebas
Organizar las pruebas en una tabla te ayudará a estructurar el razonamiento:
Entrada | Descripción | Resultado esperado | Resultado real |
---|---|---|---|
"Password1" | Contraseña válida | true | ? |
"pass1" | Muy corta | false | ? |
null | Valor nulo | false | ? |
5. Escribir pruebas con propósito
Cada caso de prueba debe:
- Verificar un aspecto del código (e.g., longitud, mayúsculas, etc.).
- Ser claro y conciso. Un caso = una prueba.
6. Pensar en «qué pasa si…»
- ¿Qué pasa si la entrada está vacía?
- ¿Qué pasa si el número es negativo?
- ¿Qué pasa si hay caracteres especiales?
Esto fomenta el pensamiento crítico y anticipa errores.
7. Usar la regla del 80/20
- El 80% de los errores suelen detectarse con el 20% de las pruebas más obvias.
- Asegúrate de cubrir los casos principales antes de preocuparte por escenarios raros.
8. Revisar y ajustar las pruebas
- Si el código cambia, los casos de prueba deben actualizarse para reflejar los nuevos requisitos.
- Revisa las pruebas para encontrar posibles errores o escenarios faltantes.
Ejemplo aplicado: Función que verifica si un número es par
Requisitos:
- Devuelve
true
si el número es par. - Devuelve
false
si es impar.
Ten en cuenta que, para crear los casos de prueba siguiendo esta guía, no es necesario conocer el código. Estamos creando casos de prueba de caja negra.
Casos de prueba organizados:
Entrada | Descripción | Resultado esperado |
---|---|---|
2 | Número par | true |
3 | Número impar | false |
0 | Caso extremo (par) | true |
-2 | Número par negativo | true |
-3 | Número impar negativo | false |
Ten en
javaCopiar código
public class TestEven { public static void main(String[] args) {
System.out.println(isEven(2)); // true
System.out.println(isEven(3)); // false
System.out.println(isEven(0)); // true
System.out.println(isEven(-2)); // true
System.out.println(isEven(-3)); // false
}
public static boolean isEven(int number) {
return number % 2 == 0;
}
}
Ejemplo aplicado: Validar contraseñas
La siguiente función estática verifica si una contraseña es suficientemente fuerte.
Código base:
public class PasswordValidator {
public static boolean isValidPassword(String password) {
if (password == null || password.length() < 8) {
return false;
}
boolean hasUppercase = false;
boolean hasLowercase = false;
boolean hasDigit = false;
for (char c : password.toCharArray()) {
if (Character.isUpperCase(c)) hasUppercase = true;
if (Character.isLowerCase(c)) hasLowercase = true;
if (Character.isDigit(c)) hasDigit = true;
}
return hasUppercase && hasLowercase && hasDigit;
}
Definir casos de prueba:
Entrada | Descripción | Resultado esperado | Resultado real |
---|---|---|---|
"Password1" | Contraseña válida | true | ? |
"Test1234" | Contraseña válida | true | ? |
"Pass1" | Muy corta | false | ? |
"password" | Solo minúsculas | false | ? |
"PASSWORD" | Solo mayúsculas | false | ? |
"12345678" | Solo números | false | ? |
null | Valor nulo | false | ? |
Probar el código haciendo uso de la consola:
Ahora vamos a implementar distintos casos de prueba usando mensajes por consola:
public static void main(String[] args) {
// Casos de prueba
System.out.println("Testing valid passwords:");
System.out.println("Password1: " + isValidPassword("Password1")); // true
System.out.println("Test1234: " + isValidPassword("Test1234")); // true
System.out.println("\nTesting invalid passwords:");
System.out.println("Pass1: " + isValidPassword("Pass1")); // false
System.out.println("password: " + isValidPassword("password")); // false
System.out.println("PASSWORD: " + isValidPassword("PASSWORD")); // false
System.out.println("12345678: " + isValidPassword("12345678")); // false
System.out.println("null: " + isValidPassword(null)); // false
}
Cómo funciona:
- Casos de prueba predefinidos: Los casos están escritos directamente en el método
main
. Puedes observar los resultados esperados en los comentarios y compararlos con la salida real. - Pruebas paso a paso: ejecuta el programa varias veces. Comprueba cómo cambia el resultado modificando las entradas en el método main.
- Resultados en consola: la salida del programa muestra claramente qué contraseñas pasan y cuáles fallan.
Variaciones para el ejercicio:
- Extender el validador: modifica el método
isValidPassword
para agregar nuevas reglas, como exigir caracteres especiales (!
,@
,#
, etc.). - Crear más casos de prueba: escribe más llamadas a
isValidPassword
con contraseñas diferentes para comprobar su robustez. - Depuración guiada: si alguna contraseña válida no pasa la validación, usa impresiones adicionales dentro del bucle. Así podrás observar el estado de las variables
hasUppercase
,hasLowercase
yhasDigit
.
Deja una respuesta