La abundancia de parámetros y valores encarece las pruebas exhaustivas de combinaciones. Las pruebas por pares reducen el número de pruebas y cubren todos los pares de valores de parámetros. Suelen equilibrar el coste de las pruebas y la probabilidad de encontrar defectos.
Por qué ayudan las pruebas por pares
Muchos defectos surgen de interacciones entre dos factores, en lugar de combinaciones poco frecuentes de cinco o seis. Cubrir todos los pares puede, por tanto, encontrar una parte considerable de los problemas con muchas menos pruebas.
Dónde aplicarlas
- →Formularios con varios campos y valores independientes.
- →Combinaciones de dispositivos, navegadores, roles, planes, países e idiomas.
- →API con numerosos parámetros y modos de invocación.
- →Matrices de compatibilidad en las que las pruebas exhaustivas resultan demasiado costosas.
Qué conviene recordar
- →Las pruebas por pares no sustituyen las pruebas de riesgos críticos del negocio ni las combinaciones peligrosas conocidas.
- →Los parámetros dependientes no deben combinarse a ciegas como si fueran independientes.
- →Excluye de antemano las combinaciones lógicamente imposibles.
- →Añade los escenarios críticos al conjunto generado de pruebas por pares.
Recomendación práctica
Utiliza las pruebas por pares para optimizar la cobertura, no para justificar el conjunto más pequeño posible. Identifica manualmente los casos de alto riesgo, añade pruebas por pares para ampliar la cobertura y después refuérzala con escenarios negativos y de límites.
Las pruebas por pares ayudan cuando el problema reside realmente en las combinaciones de parámetros. No son una solución universal para secuencias, estados o cálculos complejos.
Ejemplo desarrollado: cuatro pruebas que cubren los doce pares
Este modelo ficticio tiene tres factores: navegador (Chrome o Firefox), idioma de la interfaz (ru o en) y rol de la cuenta (viewer o editor). Se permiten las ocho combinaciones. Las versiones de los navegadores, el sistema operativo, el conjunto de datos y las banderas de funcionalidades permanecen fijos durante el ejercicio; registra sus valores exactos al ejecutar una prueba real en el navegador. Es un modelo para seleccionar entradas, no una aplicación web ejecutable.
La cobertura de todas las combinaciones requiere 2 × 2 × 2 = 8 filas. Las pruebas por pares exigen todos los pares de valores de dos factores diferentes: cuatro pares navegador–idioma, cuatro navegador–rol y cuatro idioma–rol. Las cuatro filas siguientes cubren esos doce pares.
ID Navegador Configuración regional Rol
PW1 Chrome ru viewer
PW2 Chrome en editor
PW3 Firefox ru editor
PW4 Firefox en viewerAuditar la cobertura en lugar de confiar en el número de filas
Factor A Factor B Cubierto por
Browser=Chrome Locale=ru PW1
Browser=Chrome Locale=en PW2
Browser=Firefox Locale=ru PW3
Browser=Firefox Locale=en PW4
Browser=Chrome Role=viewer PW1
Browser=Chrome Role=editor PW2
Browser=Firefox Role=viewer PW4
Browser=Firefox Role=editor PW3
Locale=ru Role=viewer PW1
Locale=ru Role=editor PW3
Locale=en Role=viewer PW4
Locale=en Role=editor PW2Cada fila de la tabla identifica un par requerido y la prueba que lo contiene. La tabla cubre cada par una vez. Cuatro pruebas constituyen el mínimo para este modelo binario sin restricciones: solo los cuatro pares navegador–idioma ya necesitan al menos cuatro filas. Esa conclusión se aplica únicamente a este modelo concreto, no a cualquier conjunto de pruebas por pares.
Verificar la matriz con Python 3
Copia este código en pairwise_coverage.py y ejecuta python3 pairwise_coverage.py. Solo utiliza la biblioteca estándar y no realiza solicitudes de red. Salida esperada: Pairs: 12/12; triples: 4/8.
from itertools import product, combinations
levels = [("Chrome", "Firefox"), ("ru", "en"), ("viewer", "editor")]
rows = [
("Chrome", "ru", "viewer"),
("Chrome", "en", "editor"),
("Firefox", "ru", "editor"),
("Firefox", "en", "viewer"),
]
required = {(i, a, j, b) for i, j in combinations(range(3), 2)
for a, b in product(levels[i], levels[j])}
covered = {(i, row[i], j, row[j]) for row in rows
for i, j in combinations(range(3), 2)}
assert all(row in set(product(*levels)) for row in rows)
assert covered == required
assert ("Chrome", "en", "viewer") not in rows
print(f"Pairs: {len(covered)}/{len(required)}; triples: {len(set(rows))}/8")Asignar un resultado esperado a cada configuración
Para una funcionalidad ficticia de documentos, define la regla antes de ejecutarla: viewer puede leer, pero un intento de edición deja intacto el contenido almacenado; editor puede guardar una edición válida exactamente una vez. En cada fila de la matriz verifica el idioma elegido, el resultado correspondiente al rol y los datos guardados. La cobertura de pares por sí sola no demuestra esos resultados; una configuración superada no constituye evidencia sin comprobaciones.
Esta matriz no detecta un defecto que solo se active con Chrome + en + viewer: esa terna está ausente aunque todos sus pares aparezcan en otras filas. Añade esa combinación cuando el riesgo o un defecto anterior lo justifiquen. Las comprobaciones de secuencias, límites, permisos y rendimiento siguen necesitando un diseño independiente. «12/12 pares» no implica ningún porcentaje de defectos encontrados.
Si una restricción del producto hace imposible una combinación, genera primero las combinaciones completas permitidas, deduce los pares alcanzables dentro de ellas y después vuelve a generar y verificar el conjunto reducido. Eliminar sin más una fila no válida puede suprimir otros pares válidos. Ejercicio: elimina PW4; los pares sin cubrir serán Firefox–en, Firefox–viewer y en–viewer. Restablece una fila válida que aporte cobertura, en lugar de reducir silenciosamente el denominador.
Seguir aprendiendo
Elegir casos adicionales según el riesgo