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.

Serie ISTQB con código

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──> SUSPENDIDA
SUSPENDIDA ──reactivar──> plan activo anterior
SUSPENDIDA ──cancelar──> CANCELADA

Transiciones válidas

DesdeAcciónHacia
GRATUITAupgrade básicoBÁSICA
GRATUITAupgrade premiumPREMIUM
BÁSICAupgrade premiumPREMIUM
GRATUITA/BÁSICA/PREMIUMcancelarCANCELADA
GRATUITA/BÁSICA/PREMIUMfalta de pagoSUSPENDIDA
SUSPENDIDAreactivarPlan anterior
SUSPENDIDAcancelarCANCELADA

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 reglas

Solo 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.

Por qué local y no una web de práctica

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

Registro Checkout Seguimiento del pedido
FlujoReglasTécnica que pide
RegistroLongitudes de usuario y contraseña, formato de emailPartición + valores límite
CheckoutTres condiciones binariasTabla de decisión
PedidoCinco estados con transiciones permitidas y prohibidasTransició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

CampoParticiónEjemploResultado
UsuarioMenos de 3qaRechazado
UsuarioEntre 3 y 20adrianaqaAceptado
UsuarioMás de 20usuario_con_mas_de_20Rechazado
EmailFormato válidoadriana@example.comAceptado
EmailSin arrobasin-arroba.example.comRechazado
EmailSin dominioadriana@Rechazado
EmailCon espaciosadriana @example.comRechazado
ContraseñaMenos de 8Clave7!Rechazado
ContraseñaEntre 8 y 20Clave123!Aceptado
ContraseñaMás de 20ClaveDemasiadoLarga123!Rechazado

Registro: valores límite

Para usuario, el rango es 3 a 20. Los valores que importan:

2, 3, 4 ← alrededor del mínimo
19, 20, 21 ← alrededor del máximo

Para contraseña, rango 8 a 20:

7, 8, 9
19, 20, 21

El 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:

ReglaAutenticadoStockPago aprobadoResultado
R1NoNoNoLOGIN_REQUIRED
R2NoNoLOGIN_REQUIRED
R3NoNoLOGIN_REQUIRED
R4NoLOGIN_REQUIRED
R5NoNoOUT_OF_STOCK
R6NoOUT_OF_STOCK
R7NoPAYMENT_REJECTED
R8ORDER_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

CREADO PAGADO PREPARANDO ENVIADO ENTREGADO
Estado actualAcciónEstado siguienteTipo
CREADOPAYPAGADOVálida
CREADOCANCELCANCELADOVálida
PAGADOPREPAREPREPARANDOVálida
PAGADOCANCELCANCELADOVálida
PREPARANDOSHIPENVIADOVálida
ENVIADODELIVERENTREGADOVálida
CREADOSHIPCREADOInválida
PAGADODELIVERPAGADOInválida
PREPARANDOCANCELPREPARANDOInválida
ENVIADOCANCELENVIADOInválida
ENTREGADOPAYENTREGADOInválida
CANCELADOPAYCANCELADOInválida
6 transiciones válidas — el camino feliz y las cancelaciones permitidas
6 transiciones inválidas — mismo número, y casi nadie las prueba

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);
});
}
});
El detalle que casi se me escapa

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.

Cuántos E2E necesitas

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.

RequisitoLo que faltaba
REG-04Ninguna prueba enviaba dos campos inválidos a la vez, así que la palabra “todos” del requisito no se estaba verificando
REG-02El diseño definía cuatro particiones de email; solo estaba automatizada la de sin arroba
ORD-05Solo se probaba cancelar desde CREADO, y el requisito también declara PAGADO
ORD-07Solo 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.

25 Tests antes de la matriz
4 Requisitos a medias
30 Tests después

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 error
showResult(
registrationResult,
"error",
`Registro rechazado: ${errors.join(", ")}`,
);
// Después: muestra solo el primero
showResult(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.

Lo que esto significa para tu suite

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:

RequisitoTécnicaPrueba
REG-01Partición + límitesusuario demasiado corto + username: longitud 2/3/20/21
REG-02Particiónemail sin arroba, email sin dominio, email con espacios
REG-03Partición + límitescontraseña demasiado corta + password: longitud 7/8/20/21
REG-04Particiónacumula los códigos de todos los campos inválidos
REG-05E2Eregistro → checkout → entrega del pedido
CHK-01Tabla de decisiónR8
CHK-02Tabla de decisiónR1, R2, R3, R4
CHK-03Tabla de decisiónR5, R6
CHK-04Tabla de decisiónR7
CHK-05Tabla + E2ER8 + flujo completo
ORD-01..04Transiciónrecorre el flujo válido hasta ENTREGADO
ORD-05Transiciónpermite cancelar un pedido creado + ...un pedido pagado
ORD-06Transiciónrechaza una transición inválida sin cambiar el estado
ORD-07Transiciónno 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écnicaTests
Partición de equivalencia6
Análisis de valores límite8
Tabla de decisión8
Transición de estados6
E2E conectado1
Total30

Córrelo tú

Terminal window
git clone https://github.com/adrianagit87/laboratorio-istqb-parte-3.git
cd laboratorio-istqb-parte-3
npm install
npx playwright install chromium
npm test

Playwright 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
ArchivoContenido
app/app.jsTodas las reglas de negocio. Es lo que vas a romper para practicar
tests/registro.spec.tsParticiones y valores límite
tests/checkout.spec.tsLas ocho reglas de la tabla de decisión
tests/pedido.spec.tsTransiciones válidas e inválidas
tests/e2e.spec.tsEl flujo conectado de punta a punta
docs/requisitos.mdLos 17 requisitos numerados
docs/diseno-de-pruebas.mdParticiones, límites y tablas antes de automatizar
docs/trazabilidad.mdLa matriz, incluidos los huecos que destapó
docs/solucion-suscripciones.mdEl ejercicio de la Parte 2 resuelto
docs/evidencia-*.txtSalidas 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écnicaTe diceSeñal de que la necesitas
Partición de equivalenciaQué grupos de valores probarEl campo acepta rangos o categorías
Valores límiteDónde exactamente probarHay un mínimo y un máximo
Tabla de decisiónQué combinaciones probarEl resultado depende de varias condiciones
Transición de estadosQué caminos y qué muros probarAlgo cambia de estado con el tiempo
Matriz de trazabilidadQué te falta por probarSiempre
17 Requisitos numerados
30 Tests en verde
2 Regresiones verificadas

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.