En la Parte 1 vimos partición de equivalencia y valores límite. En la Parte 2, tablas de decisión y transición de estados. Cuatro técnicas, cada una explicada con su bug real.
El problema de explicar técnicas de a una es que en tu trabajo nunca llegan de a una. Llega un requerimiento con un formulario, unas reglas de negocio y un flujo con estados, todo junto, y tienes que decidir qué técnica va dónde.
Eso es lo que hacemos hoy. Un ecommerce completo, 17 requisitos numerados, una suite de 30 tests en Playwright. Todo el código corrió antes de que yo escribiera una línea de este artículo.
Esta es la Parte 3 de 3. Cierra la trilogía. Si te faltan las anteriores, léelas primero — aquí doy por sabidas las cuatro técnicas y me concentro en cómo se conectan.
Primero: la deuda de la Parte 2
Te dejé un ejercicio de transición de estados con un sistema de suscripciones. Aquí está la solución antes de cualquier otra cosa.
Los estados
GRATUITA ──upgrade──> BÁSICA ──upgrade──> PREMIUM │ │ │ └────upgrade─────────┘ │ │ │ │ └────cancelar────────┴────cancelar────────┴──> CANCELADA
Cualquier plan activo ──falta de pago──> SUSPENDIDASUSPENDIDA ──reactivar──> plan activo anteriorSUSPENDIDA ──cancelar──> CANCELADATransiciones válidas
| Desde | Acción | Hacia |
|---|---|---|
| GRATUITA | upgrade básico | BÁSICA |
| GRATUITA | upgrade premium | PREMIUM |
| BÁSICA | upgrade premium | PREMIUM |
| GRATUITA/BÁSICA/PREMIUM | cancelar | CANCELADA |
| GRATUITA/BÁSICA/PREMIUM | falta de pago | SUSPENDIDA |
| SUSPENDIDA | reactivar | Plan anterior |
| SUSPENDIDA | cancelar | CANCELADA |
Transiciones inválidas
- PREMIUM → BÁSICA: el downgrade no está permitido.
- BÁSICA → GRATUITA: mismo caso.
- CANCELADA → cualquier plan: es terminal dentro del alcance del ejercicio.
- SUSPENDIDA → PREMIUM por upgrade: primero tiene que reactivarse al plan anterior.
Si tu lista de inválidas quedó más corta que la de válidas, revisa. Casi siempre hay más caminos prohibidos que permitidos, y son los que nadie prueba.
Los datos de prueba
const subscriptionTransitions = [ { from: "GRATUITA", action: "UPGRADE_BASIC", expected: "BÁSICA", valid: true, }, { from: "GRATUITA", action: "UPGRADE_PREMIUM", expected: "PREMIUM", valid: true, }, { from: "BÁSICA", action: "UPGRADE_PREMIUM", expected: "PREMIUM", valid: true, }, { from: "PREMIUM", action: "DOWNGRADE_BASIC", expected: "PREMIUM", valid: false, }, { from: "SUSPENDIDA", action: "CANCEL", expected: "CANCELADA", valid: true },];Fíjate en la fila inválida: expected es PREMIUM, el mismo estado de partida. Una transición prohibida tiene que dejar el sistema donde estaba. Verificar solo el mensaje de error deja pasar el bug en el que el sistema muestra el error y además cambia el estado.
El bonus
Tres condiciones binarias para el upgrade a Premium —tarjeta válida, email verificado, sin deuda— dan:
2³ = 8 reglasSolo Sí / Sí / Sí aprueba el upgrade. Las ocho se escriben antes de reducir nada.
Deuda pagada. Vamos a lo grande.
El laboratorio
Construí un ecommerce mínimo que corre en tu máquina. Tres flujos: registro, checkout y seguimiento del pedido.
Podía haber usado una tienda de demo pública. No lo hice porque esas webs cambian sin avisar, a veces están caídas, y cuando un test falla nunca sabes si el bug es tuyo o de ellos. Un laboratorio que enseña diseño de pruebas tiene que ser determinista: mismo input, mismo resultado, hoy y en seis meses.
El repositorio está entero al final del artículo, con instrucciones para clonarlo y correrlo.
Los tres flujos
| Flujo | Reglas | Técnica que pide |
|---|---|---|
| Registro | Longitudes de usuario y contraseña, formato de email | Partición + valores límite |
| Checkout | Tres condiciones binarias | Tabla de decisión |
| Pedido | Cinco estados con transiciones permitidas y prohibidas | Transición de estados |
Ninguna técnica sirve para los tres. Cada flujo pide la suya, y reconocerlo es la mitad del trabajo del QA que diseña.
Paso 1: numerar los requisitos antes de tocar nada
Este es el paso que más gente se salta y el que más caro sale.
Antes de diseñar un solo caso, escribí los requisitos con un ID cada uno. No un documento bonito — una lista con identificadores para poder apuntar a ellos después.
REG-01: El nombre de usuario acepta entre 3 y 20 caracteres, ambos incluidos.REG-02: El email debe tener texto antes de @, texto después, un punto y texto después del punto; no acepta espacios.REG-03: La contraseña acepta entre 8 y 20 caracteres, ambos incluidos.REG-04: Si algún campo incumple su regla, el registro se rechaza y muestra los códigos de TODOS los errores encontrados.REG-05: Un registro válido marca al usuario como autenticado para el checkout.
CHK-01: Una compra solo crea pedido si hay autenticación, stock y pago aprobado.CHK-02: Sin autenticación, el resultado es LOGIN_REQUIRED.CHK-03: Con autenticación y sin stock, el resultado es OUT_OF_STOCK.CHK-04: Con autenticación, stock y pago rechazado: PAYMENT_REJECTED.CHK-05: Con las tres condiciones: ORDER_CREATED y el pedido queda en CREADO.
ORD-01: CREADO permite pagar y pasa a PAGADO.ORD-02: PAGADO permite preparar y pasa a PREPARANDO.ORD-03: PREPARANDO permite enviar y pasa a ENVIADO.ORD-04: ENVIADO permite entregar y pasa a ENTREGADO.ORD-05: CREADO y PAGADO permiten cancelar y pasan a CANCELADO.ORD-06: Cualquier acción no declarada se rechaza con TRANSITION_NOT_ALLOWED y no cambia el estado.ORD-07: ENTREGADO y CANCELADO son terminales.17 requisitos. Cada uno se puede verificar con un test que pasa o falla, sin discusión.
Un requisito que no puedes convertir en un assert no es un requisito. Es una intención.
Guarda ese ID. Más adelante en el artículo, REG-04 nos va a dar la lección más importante de todo el laboratorio.
Paso 2: diseñar antes de automatizar
Con los requisitos numerados, cada técnica va a lo suyo.
Registro: particiones
| Campo | Partición | Ejemplo | Resultado |
|---|---|---|---|
| Usuario | Menos de 3 | qa | Rechazado |
| Usuario | Entre 3 y 20 | adrianaqa | Aceptado |
| Usuario | Más de 20 | usuario_con_mas_de_20 | Rechazado |
| Formato válido | adriana@example.com | Aceptado | |
| Sin arroba | sin-arroba.example.com | Rechazado | |
| Sin dominio | adriana@ | Rechazado | |
| Con espacios | adriana @example.com | Rechazado | |
| Contraseña | Menos de 8 | Clave7! | Rechazado |
| Contraseña | Entre 8 y 20 | Clave123! | Aceptado |
| Contraseña | Más de 20 | ClaveDemasiadoLarga123! | Rechazado |
Registro: valores límite
Para usuario, el rango es 3 a 20. Los valores que importan:
2, 3, 4 ← alrededor del mínimo19, 20, 21 ← alrededor del máximoPara contraseña, rango 8 a 20:
7, 8, 919, 20, 21El n+1 del máximo —el 21— es el que más bugs encuentra en mi experiencia real. Es donde el desarrollador escribió < en vez de <=, o al revés.
Checkout: la tabla completa
Tres condiciones binarias, 2³ = 8 reglas. Las escribo todas contando en binario ascendente, para que se vea de dónde sale el 8:
| Regla | Autenticado | Stock | Pago aprobado | Resultado |
|---|---|---|---|---|
| R1 | No | No | No | LOGIN_REQUIRED |
| R2 | No | No | Sí | LOGIN_REQUIRED |
| R3 | No | Sí | No | LOGIN_REQUIRED |
| R4 | No | Sí | Sí | LOGIN_REQUIRED |
| R5 | Sí | No | No | OUT_OF_STOCK |
| R6 | Sí | No | Sí | OUT_OF_STOCK |
| R7 | Sí | Sí | No | PAYMENT_REJECTED |
| R8 | Sí | Sí | Sí | ORDER_CREATED |
Mira la columna de la derecha. R1 a R4 dan lo mismo, y R5 con R6 también. En el examen te van a pedir reducir la tabla: si la autenticación falla, las otras dos condiciones dan igual, así que esas cuatro reglas colapsan en una con guiones.
En el laboratorio dejé las ocho. La reducción es correcta para el examen y para ahorrar tests. Cuando la aplicas antes de tiempo, escondes la combinación rara justo antes de que alguien cambie el orden de las validaciones en el código.
Pedido: el mapa de estados
| Estado actual | Acción | Estado siguiente | Tipo |
|---|---|---|---|
| CREADO | PAY | PAGADO | Válida |
| CREADO | CANCEL | CANCELADO | Válida |
| PAGADO | PREPARE | PREPARANDO | Válida |
| PAGADO | CANCEL | CANCELADO | Válida |
| PREPARANDO | SHIP | ENVIADO | Válida |
| ENVIADO | DELIVER | ENTREGADO | Válida |
| CREADO | SHIP | CREADO | Inválida |
| PAGADO | DELIVER | PAGADO | Inválida |
| PREPARANDO | CANCEL | PREPARANDO | Inválida |
| ENVIADO | CANCEL | ENVIADO | Inválida |
| ENTREGADO | PAY | ENTREGADO | Inválida |
| CANCELADO | PAY | CANCELADO | Inválida |
Paso 3: el código
Todo el diseño de arriba se traduce a arrays. Los tests salen de recorrerlos.
Registro: particiones y límites
import { expect, test } from "@playwright/test";
const validUser = { username: "adrianaqa", email: "adriana@example.com", password: "segura123",};
async function submitRegistration(page, data) { await page.getByLabel("Nombre de usuario").fill(data.username); await page.getByLabel("Email").fill(data.email); await page.getByLabel("Contraseña").fill(data.password); await page.getByRole("button", { name: "Crear cuenta" }).click();}
test.describe("Registro — particiones de equivalencia", () => { const cases = [ { name: "datos válidos", data: validUser, expected: "Cuenta creada correctamente", }, { name: "usuario demasiado corto", data: { ...validUser, username: "ab" }, expected: "USERNAME_LENGTH", }, { name: "email sin arroba", data: { ...validUser, email: "sin-arroba.example.com" }, expected: "EMAIL_INVALID", }, { name: "email sin dominio", data: { ...validUser, email: "adriana@" }, expected: "EMAIL_INVALID", }, { name: "email con espacios", data: { ...validUser, email: "adriana @example.com" }, expected: "EMAIL_INVALID", }, { name: "contraseña demasiado corta", data: { ...validUser, password: "1234567" }, expected: "PASSWORD_LENGTH", }, ];
for (const { name, data, expected } of cases) { test(name, async ({ page }) => { await page.goto("/"); await submitRegistration(page, data); await expect(page.locator("#registration-result")).toContainText( expected, ); }); }});Los valores límite salen del mismo patrón, generando la cadena con repeat:
test.describe("Registro — análisis de valores límite", () => { const boundaries = [ { field: "username", length: 2, valid: false }, { field: "username", length: 3, valid: true }, { field: "username", length: 20, valid: true }, { field: "username", length: 21, valid: false }, { field: "password", length: 7, valid: false }, { field: "password", length: 8, valid: true }, { field: "password", length: 20, valid: true }, { field: "password", length: 21, valid: false }, ] as const;
for (const boundary of boundaries) { test(`${boundary.field}: longitud ${boundary.length}`, async ({ page }) => { const data = { ...validUser, [boundary.field]: "a".repeat(boundary.length), };
await page.goto("/"); await submitRegistration(page, data);
await expect(page.locator("#registration-result")).toContainText( boundary.valid ? "Cuenta creada correctamente" : `${boundary.field.toUpperCase()}_LENGTH`, ); }); }});Ocho tests de una tabla de ocho filas. Si mañana el rango cambia de 3-20 a 5-30, tocas cuatro números y los tests se adaptan.
Checkout: las ocho reglas
// El orden y los IDs son los mismos de la tabla de diseño: las tres// condiciones cuentan en binario ascendente, de No/No/No hasta Sí/Sí/Sí.const rules = [ { id: "R1", authenticated: false, inStock: false, payment: false, result: "LOGIN_REQUIRED", }, { id: "R2", authenticated: false, inStock: false, payment: true, result: "LOGIN_REQUIRED", }, { id: "R3", authenticated: false, inStock: true, payment: false, result: "LOGIN_REQUIRED", }, { id: "R4", authenticated: false, inStock: true, payment: true, result: "LOGIN_REQUIRED", }, { id: "R5", authenticated: true, inStock: false, payment: false, result: "OUT_OF_STOCK", }, { id: "R6", authenticated: true, inStock: false, payment: true, result: "OUT_OF_STOCK", }, { id: "R7", authenticated: true, inStock: true, payment: false, result: "PAYMENT_REJECTED", }, { id: "R8", authenticated: true, inStock: true, payment: true, result: "ORDER_CREATED", },];
test.describe("Checkout — tabla de decisión completa", () => { for (const rule of rules) { test(`${rule.id}: devuelve ${rule.result}`, async ({ page }) => { await page.goto("/"); await page .getByLabel("Usuario autenticado") .setChecked(rule.authenticated); await page.getByLabel("Producto con stock").setChecked(rule.inStock); await page.getByLabel("Pago aprobado").setChecked(rule.payment); await page.getByRole("button", { name: "Confirmar compra" }).click();
await expect(page.locator("#checkout-result")).toHaveText(rule.result); }); }});La primera versión de este archivo tenía los IDs al revés: R1 era Sí/Sí/Sí y
R8 era No/No/No. Los ocho tests pasaban, porque cada fila era coherente
consigo misma. Pero el documento de diseño decía lo contrario. Alguien que
leyera la tabla, buscara R1 en la salida de Playwright y viera
ORDER_CREATED donde la tabla dice LOGIN_REQUIRED habría perdido media
tarde. Cuando el diseño y el código no comparten los mismos IDs, la
trazabilidad se rompe aunque todo esté verde.
Fíjate también en setChecked(valor) en vez de un if con check(). Al pasarle el booleano directo, el test deja el checkbox en el estado que dice la tabla sin importar cómo estaba antes.
Pedido: caminos y muros
test.beforeEach(async ({ page }) => { await page.goto("/"); await page.getByRole("button", { name: "Reiniciar" }).click();});
test("recorre el flujo válido hasta ENTREGADO", async ({ page }) => { const flow = [ { action: "Pagar", state: "PAGADO" }, { action: "Preparar", state: "PREPARANDO" }, { action: "Enviar", state: "ENVIADO" }, { action: "Entregar", state: "ENTREGADO" }, ];
for (const step of flow) { await page.getByRole("button", { name: step.action, exact: true }).click(); await expect(page.locator("#order-state")).toHaveText(step.state); }});
test("rechaza una transición inválida sin cambiar el estado", async ({ page,}) => { await page.getByRole("button", { name: "Enviar", exact: true }).click();
await expect(page.locator("#order-result")).toHaveText( "TRANSITION_NOT_ALLOWED: CREADO + SHIP", ); await expect(page.locator("#order-state")).toHaveText("CREADO");});Las dos aserciones del segundo test son el punto. La primera comprueba que el sistema avisa. La segunda, que no se movió. Un sistema puede mostrarte el error perfecto y cambiar el estado igual, y ese bug se escapa si solo miras el mensaje.
El beforeEach con el botón Reiniciar existe porque la app guarda el estado del pedido en localStorage. Sin ese reinicio, cada test heredaría el estado del anterior y tendrías tests que pasan solos y fallan en grupo. El clásico flaky que no es flaky: es contaminación de estado.
El test que conecta todo
test("registro → checkout → entrega del pedido", async ({ page }) => { await page.goto("/");
await page.getByLabel("Nombre de usuario").fill("adrianaqa"); await page.getByLabel("Email").fill("adriana@example.com"); await page.getByLabel("Contraseña").fill("segura123"); await page.getByRole("button", { name: "Crear cuenta" }).click(); await expect(page.locator("#registration-result")).toHaveText( "Cuenta creada correctamente", );
await expect(page.getByLabel("Usuario autenticado")).toBeChecked(); await page.getByLabel("Producto con stock").check(); await page.getByLabel("Pago aprobado").check(); await page.getByRole("button", { name: "Confirmar compra" }).click(); await expect(page.locator("#checkout-result")).toHaveText("ORDER_CREATED");
for (const action of ["Pagar", "Preparar", "Enviar", "Entregar"]) { await page.getByRole("button", { name: action, exact: true }).click(); } await expect(page.locator("#order-state")).toHaveText("ENTREGADO");});Un solo test E2E. Uno. La línea que verifica el checkbox de autenticado cubre REG-05, que es la costura entre el registro y el checkout: el único requisito que ninguna técnica individual verifica, porque vive entre dos flujos.
Uno por flujo de negocio crítico, no uno por caso. Las combinaciones ya las cubren los tests de cada técnica, que corren en milisegundos. El E2E existe para verificar que las piezas están conectadas. Si tienes 40 tests E2E, no tienes cobertura: tienes una suite lenta que se cae entera cuando alguien cambia un selector del login.
25 en verde. Y entonces llené la matriz.
Con esos cuatro archivos, la suite quedó así:
25 passed (9.2s)Todo verde. Las cuatro técnicas aplicadas. En ese punto yo habría publicado el artículo.
Antes de escribir, hice el último paso del método: llenar la matriz de trazabilidad. Una tabla con una fila por requisito y la prueba que lo verifica.
Y aparecieron cuatro agujeros.
| Requisito | Lo que faltaba |
|---|---|
| REG-04 | Ninguna prueba enviaba dos campos inválidos a la vez, así que la palabra “todos” del requisito no se estaba verificando |
| REG-02 | El diseño definía cuatro particiones de email; solo estaba automatizada la de sin arroba |
| ORD-05 | Solo se probaba cancelar desde CREADO, y el requisito también declara PAGADO |
| ORD-07 | Solo se probaba que CANCELADO es terminal; faltaba ENTREGADO |
Cuatro requisitos con cobertura a medias, con la suite entera en verde y cuatro técnicas correctamente aplicadas.
El verde no te dice si cubriste los requisitos. Te dice que lo que decidiste probar, funciona. La matriz de trazabilidad es lo que te dice si decidiste bien.
Cerrarlos costó cinco tests —el hueco de email eran dos particiones distintas— y la suite pasó a 30. El código de la aplicación no cambió ni una línea. Los cinco casos nuevos pasaron a la primera. No había bugs escondidos esperando: había requisitos que nadie estaba mirando.
La prueba de que la suite sabe fallar
Cinco tests nuevos que pasan el día que los escribes no han demostrado nada todavía. Un test que nunca falló es una promesa sin firmar.
Así que rompí la aplicación a propósito. En el código del registro, cambié esto:
// Antes: muestra todos los códigos de errorshowResult( registrationResult, "error", `Registro rechazado: ${errors.join(", ")}`,);
// Después: muestra solo el primeroshowResult(registrationResult, "error", `Registro rechazado: ${errors[0]}`);Un bug realista. El tipo de cambio que alguien hace pensando “la interfaz se ve más limpia con un solo mensaje”. Resultado:
1 failed [chromium] › registro.spec.ts:60 › acumula los códigos de todos los campos inválidos Expected: "Registro rechazado: USERNAME_LENGTH, EMAIL_INVALID, PASSWORD_LENGTH" Received: "Registro rechazado: USERNAME_LENGTH"
29 passed (9.2s)Falló una prueba. La que acabábamos de escribir para cerrar el hueco de REG-04.
Lo importante está en las otras 29. Los tres casos que envían un solo campo inválido siguieron verdes, porque cada uno seguía viendo su propio código de error. Los ocho de la tabla de decisión, verdes. Los ocho de valores límite, verdes. El E2E, verde.
Con la suite original de 25 tests, ese bug llegaba a producción con todo en verde y nadie se enteraba.
Si tienes un requisito que dice “muestra todos los errores”, “notifica a todos los usuarios” o “valida todos los campos”, busca ahora mismo si tienes un test con más de un caso inválido a la vez. Los requisitos con la palabra todos casi nunca están cubiertos, porque la costumbre es probar un problema por test. Es una limpieza de diez minutos y suele aparecer algo.
Hay una segunda regresión documentada en el laboratorio: cambiar el máximo de username de 20 a 21. Falla el caso de longitud 21 y solo ese. Es la demostración de por qué el n+1 merece su propio test.
La matriz completa
Este es el entregable que cierra el círculo. Requisito, técnica, prueba:
| Requisito | Técnica | Prueba |
|---|---|---|
| REG-01 | Partición + límites | usuario demasiado corto + username: longitud 2/3/20/21 |
| REG-02 | Partición | email sin arroba, email sin dominio, email con espacios |
| REG-03 | Partición + límites | contraseña demasiado corta + password: longitud 7/8/20/21 |
| REG-04 | Partición | acumula los códigos de todos los campos inválidos |
| REG-05 | E2E | registro → checkout → entrega del pedido |
| CHK-01 | Tabla de decisión | R8 |
| CHK-02 | Tabla de decisión | R1, R2, R3, R4 |
| CHK-03 | Tabla de decisión | R5, R6 |
| CHK-04 | Tabla de decisión | R7 |
| CHK-05 | Tabla + E2E | R8 + flujo completo |
| ORD-01..04 | Transición | recorre el flujo válido hasta ENTREGADO |
| ORD-05 | Transición | permite cancelar un pedido creado + ...un pedido pagado |
| ORD-06 | Transición | rechaza una transición inválida sin cambiar el estado |
| ORD-07 | Transición | no permite modificar un pedido cancelado + ...entregado |
Las dos columnas cierran. Cada requisito tiene prueba, cada prueba responde a un requisito. Sin filas huérfanas de ningún lado.
Una fila huérfana del lado izquierdo es un requisito sin probar. Del lado derecho es un test que nadie sabe por qué existe, que es el que nadie se atreve a borrar cuando empieza a fallar.
El reparto final
| Técnica | Tests |
|---|---|
| Partición de equivalencia | 6 |
| Análisis de valores límite | 8 |
| Tabla de decisión | 8 |
| Transición de estados | 6 |
| E2E conectado | 1 |
| Total | 30 |
Córrelo tú
git clone https://github.com/adrianagit87/laboratorio-istqb-parte-3.gitcd laboratorio-istqb-parte-3npm installnpx playwright install chromiumnpm testPlaywright levanta la aplicación solo. No necesitas arrancar nada aparte ni tener internet.
Cuando lo tengas en verde, haz el ejercicio de verdad: entra a app/app.js, rompe algo a propósito y mira quién se queja. Empieza por cambiar un <= por un < en las longitudes. Después borra una fila de transitions. Un test que no sabes fallar no es un test que conoces.
Qué hay en cada archivo del laboratorio
| Archivo | Contenido |
|---|---|
app/app.js | Todas las reglas de negocio. Es lo que vas a romper para practicar |
tests/registro.spec.ts | Particiones y valores límite |
tests/checkout.spec.ts | Las ocho reglas de la tabla de decisión |
tests/pedido.spec.ts | Transiciones válidas e inválidas |
tests/e2e.spec.ts | El flujo conectado de punta a punta |
docs/requisitos.md | Los 17 requisitos numerados |
docs/diseno-de-pruebas.md | Particiones, límites y tablas antes de automatizar |
docs/trazabilidad.md | La matriz, incluidos los huecos que destapó |
docs/solucion-suscripciones.md | El ejercicio de la Parte 2 resuelto |
docs/evidencia-*.txt | Salidas reales de las ejecuciones en verde y en rojo |
Qué llevarte a tu proyecto el lunes
El laboratorio es un ecommerce de juguete. El método no.
1. Numera los requisitos antes de diseñar casos. Aunque el equipo no tenga documentación formal, aunque los saques de una conversación en Slack. Sin IDs no hay trazabilidad, y sin trazabilidad no sabes qué te falta.
2. Elige la técnica según la forma del problema. Campo con rango, partición y límites. Reglas que se combinan, tabla de decisión. Algo que cambia de estado, transición. Si estás usando la misma técnica para todo, estás dejando cosas fuera.
3. Escribe la tabla completa antes de reducirla. La reducción es válida. Hacerla de memoria y sin haber escrito las combinaciones es lo que esconde la regla rara.
4. Prueba las transiciones prohibidas con dos aserciones. El mensaje de error y el estado que no cambió.
5. Llena la matriz de trazabilidad aunque la suite esté verde. Es el paso que en este laboratorio destapó cuatro requisitos a medias en una suite que yo daba por terminada.
6. Rompe algo a propósito una vez. Si tocas una regla de negocio y ningún test se queja, acabas de encontrar tu próximo caso de prueba.
Cheat sheet de la trilogía
| Técnica | Te dice | Señal de que la necesitas |
|---|---|---|
| Partición de equivalencia | Qué grupos de valores probar | El campo acepta rangos o categorías |
| Valores límite | Dónde exactamente probar | Hay un mínimo y un máximo |
| Tabla de decisión | Qué combinaciones probar | El resultado depende de varias condiciones |
| Transición de estados | Qué caminos y qué muros probar | Algo cambia de estado con el tiempo |
| Matriz de trazabilidad | Qué te falta por probar | Siempre |
Cierre de la trilogía
Tres partes, cuatro técnicas y un laboratorio que puedes clonar. Si llegaste hasta aquí, ya tienes lo que el Capítulo 4 del syllabus pide para el examen, y algo que el examen no te pide: la costumbre de comprobar que tus tests saben fallar.
La certificación te la dan por reconocer las técnicas en un test de opción múltiple. El trabajo te lo dan por aplicarlas a un requerimiento que llegó a medias un martes por la tarde. Este laboratorio existe para lo segundo.
Si haces el ejercicio de romper la aplicación y encuentras algo que ningún test detecta, escríbeme. Esos son los casos que quiero para la próxima serie.