📋 Guía de Aula Invertida
— vistas

Testing contra Criterios de Aceptación y Definition of Done

Valentina terminó la historia "reservar un espacio" de EventoUAB, la probó una vez y funcionó. ¿Está terminada? Esta guía parte de los criterios de aceptación que ya escribiste, los convierte en casos de prueba normales, inválidos y de borde, y fija la lista de chequeo del equipo —la Definition of Done— que decide cuándo una historia se puede cerrar.

RC
Ing. Roy Carrasco
Facultad de Ingeniería de Sistemas · UAB

Bienvenido

Es viernes del Sprint 1 en EventoUAB. Valentina abre el calendario, reserva el auditorio de 14:00 a 16:00 y la reserva aparece en "mis reservas". Dice: "Listo, lo probé y anda." Mateo, que está por revisar su Pull Request, le hace una sola pregunta: "¿Probaste qué pasa con exactamente 4 horas?" Valentina no lo probó.

Esa pregunta es el tema de la guía. Probar que algo funciona una vez no es lo mismo que comprobar que cumple lo que prometía la historia. Lo primero lo hace cualquiera con un clic; lo segundo requiere partir de los criterios de aceptación y recorrerlos con intención.

Objetivo del módulo

Al finalizar esta guía sabrás convertir cada criterio de aceptación en casos de prueba normales, inválidos y de borde, escribirlos como pruebas automáticas en Node.js, entender por qué los casos de borde atrapan errores que los demás dejan pasar, y distinguir los criterios de aceptación de una historia de la Definition of Done de todo el equipo.

📝 Actividades de este módulo

Encontrarás actividades cortas y autocorregibles —selección múltiple, clasificación, emparejamiento y completar espacios— repartidas a lo largo de la guía, y una sección de ejercicios de razonamiento donde se te da un escenario y debés decidir antes de comprobar.

🎯 Del criterio al caso

Cada "Dado / Cuando / Entonces" ya es, casi literal, una prueba.

🧪 Tres familias

Normal, inválido y de borde: qué cubre cada una y cuál suele olvidarse.

✅ Definition of Done

La lista que el equipo acuerda una vez y aplica a todas las historias.

Del criterio a la prueba

En la guía de historias de usuario escribiste criterios con el formato Dado / Cuando / Entonces. Ese formato no es casualidad: tiene la misma forma que una prueba automática, que siempre hace tres cosas en orden.

En el criterioEn la pruebaEjemplo en EventoUAB
Dado que...Preparar: dejar el sistema en el estado inicial.El auditorio está libre de 14:00 a 16:00.
Cuando...Ejecutar: llamar a la función con la acción.El club pide reservar de 14:00 a 16:00.
Entonces...Comprobar: afirmar el resultado esperado.La reserva queda registrada y el espacio ocupado.
Un criterio no alcanza con un solo caso

Los criterios dicen qué debe cumplirse. Para comprobarlo hace falta pensar con qué datos: un criterio como "una reserva dura como máximo 4 horas" se prueba con más de un valor, y los valores que importan son los que están justo en el límite.

Emparejamiento

Une cada parte del criterio con lo que hace en una prueba.

Normal, inválido y de borde

Para cada criterio conviene pensar tres familias de casos. Un equipo apurado suele escribir solo la primera; la mayoría de los errores que llegan a producción viven en las otras dos.

FamiliaQué pruebaEn "reservar un espacio"
NormalEl camino feliz: datos correctos, todo sale bien.Reservar el auditorio de 14:00 a 16:00 estando libre.
InválidoDatos o situaciones que el sistema debe rechazar con un error claro.Reservar un horario ya ocupado; fin anterior al inicio.
BordeValores justo en el límite de una regla, donde cambia la respuesta.Exactamente 4 horas; empezar justo cuando termina otra reserva.
Cómo encontrar los bordes

Buscá en cada criterio un número, un límite o una comparación ("máximo", "al menos", "antes de", "no se solapan"). Probá el valor exacto, uno apenas por debajo y uno apenas por encima. Si el criterio no tiene ningún límite, probablemente tampoco tenga casos de borde — y está bien.

Clasificación

La regla es "una reserva no puede durar más de 4 horas ni solaparse con otra". ¿A qué familia pertenece cada caso de prueba?

Reservar el auditorio de 14:00 a 16:00 cuando está libre.
Reservar de 10:00 a 14:00, exactamente el máximo permitido de 4 horas.
Reservar con una hora de fin anterior a la hora de inicio.
Pedir de 16:00 a 18:00 un espacio que otro club tiene de 15:00 a 17:00.
Pedir de 16:00 a 18:00 un espacio que otro club libera justo a las 16:00.
Cancelar una reserva propia que existe y todavía no empezó.

Las pruebas en código

Probar a mano cada caso en cada cambio no escala. Una prueba automática guarda el caso como código y lo vuelve a correr en segundos. Esta es la función que escribió Valentina, con las tres reglas de la historia: fin posterior al inicio, máximo 4 horas y sin solapamiento.

Node.js — reservas.js
const DURACION_MAX_HORAS = 4;

export function reservar(reservas, espacioId, inicio, fin) {
  if (fin <= inicio) {
    throw new Error("La hora de fin debe ser posterior al inicio");
  }
  const horas = (fin - inicio) / 3600000;
  if (horas > DURACION_MAX_HORAS) {
    throw new Error("Máximo 4 horas por reserva");
  }
  const choca = reservas.some(
    (r) => r.espacioId === espacioId && r.inicio < fin && r.fin > inicio
  );
  if (choca) {
    throw new Error("Espacio ocupado en ese horario");
  }
  const nueva = { espacioId, inicio, fin };
  reservas.push(nueva);
  return nueva;
}

Y estas son las pruebas, una por cada caso que pensamos arriba. Cada una sigue el mismo orden: preparar, ejecutar, comprobar. Usan el corredor de pruebas que ya trae Node (node:test), sin instalar nada.

Node.js — reservas.test.js
import { test } from "node:test";
import assert from "node:assert/strict";
import { reservar } from "./reservas.js";

const h = (hora, min = 0) => new Date(2026, 9, 20, hora, min);

test("normal: espacio libre, la reserva queda registrada", () => {
  const reservas = [];                                    // Dado
  reservar(reservas, "auditorio", h(14), h(16));          // Cuando
  assert.equal(reservas.length, 1);                       // Entonces
});

test("inválido: horario ya ocupado, se rechaza y no se duplica", () => {
  const reservas = [{ espacioId: "auditorio", inicio: h(14), fin: h(16) }];
  assert.throws(() => reservar(reservas, "auditorio", h(15), h(17)), /ocupado/);
  assert.equal(reservas.length, 1);
});

test("inválido: fin anterior al inicio", () => {
  assert.throws(() => reservar([], "auditorio", h(16), h(14)), /posterior/);
});

test("borde: exactamente 4 horas se acepta", () => {
  const reservas = [];
  reservar(reservas, "auditorio", h(10), h(14));
  assert.equal(reservas.length, 1);
});

test("borde: 4 horas y 1 minuto se rechaza", () => {
  assert.throws(() => reservar([], "auditorio", h(10), h(14, 1)), /Máximo/);
});

test("borde: empieza justo cuando termina otra, no es choque", () => {
  const reservas = [{ espacioId: "auditorio", inicio: h(14), fin: h(16) }];
  reservar(reservas, "auditorio", h(16), h(18));
  assert.equal(reservas.length, 2);
});

test("borde: inicio y fin iguales se rechaza", () => {
  assert.throws(() => reservar([], "auditorio", h(14), h(14)), /posterior/);
});
Terminal — node --test
✔ normal: espacio libre, la reserva queda registrada
✔ inválido: horario ya ocupado, se rechaza y no se duplica
✔ inválido: fin anterior al inicio
✔ borde: exactamente 4 horas se acepta
✔ borde: 4 horas y 1 minuto se rechaza
✔ borde: empieza justo cuando termina otra, no es choque
✔ borde: inicio y fin iguales se rechaza
ℹ tests 7   ℹ pass 7   ℹ fail 0
Cada prueba nace de un criterio

Fijate que ninguna prueba menciona clases ni detalles internos: todas hablan del comportamiento que prometía la historia. Si mañana el equipo reescribe reservar por dentro, las mismas pruebas siguen sirviendo — y avisan si el comportamiento cambió.

Razonamiento

Valentina probó "reservar" una sola vez, con un espacio libre, y salió bien. Mirando los criterios de la historia, ¿qué le falta cubrir?

Completar

Criterio: "una reserva dura como máximo 4 horas". Armá el caso de borde para ese límite.

Dado un espacio , cuando el club pide una reserva de , entonces el sistema .

Por qué importa el borde

Una prueba que pasa te dice algo concreto: ese caso funciona. No te dice que todo funciona. Para ver por qué los casos de borde pesan tanto, hagamos un experimento: introducir a propósito un error chico y ver qué prueba lo detecta.

El experimento

Un cambio de una sola línea en reservar, del tipo que se cuela en un apuro o lo sugiere una IA sin que nadie lo note: horas > DURACION_MAX_HORAS pasa a horas >= DURACION_MAX_HORAS. Parece inocente, pero ahora una reserva de exactamente 4 horas se rechaza.

PruebaCon el error
normal: espacio libre, la reserva queda registrada✔ pasa
inválido: horario ya ocupado✔ pasa
inválido: fin anterior al inicio✔ pasa
borde: exactamente 4 horas se acepta✖ falla
borde: 4 horas y 1 minuto se rechaza✔ pasa
borde: empieza justo cuando termina otra✔ pasa
borde: inicio y fin iguales✔ pasa

Resultado real de correr las siete pruebas contra el código modificado: seis siguen en verde y solo el borde exacto de 4 horas detecta el error. Con un cambio parecido en la regla de solapamiento (r.fin > inicio por r.fin >= inicio), el único que falla es el caso "empieza justo cuando termina otra".

La lección práctica

Un equipo que solo escribió el caso normal y los inválidos habría visto todo en verde y habría entregado un error. Los errores de comparación (< contra <=) solo se manifiestan en el límite exacto, no en valores intermedios. Por eso cada límite del criterio merece su caso.

Razonamiento

Alguien cambia > por >= en la regla de duración máxima y los casos normal e inválidos siguen en verde. ¿Qué conclusión es correcta?

Definition of Done

Los criterios de aceptación dicen cuándo esta historia hace lo que prometía. Pero una historia puede cumplirlos todos y seguir sin estar lista para entregarse: sin revisar, sin integrar, sin pruebas. Para eso existe la Definition of Done (DoD): una lista de chequeo que el equipo acuerda una vez y aplica a todas sus historias.

Criterios de aceptaciónDefinition of Done
Pertenece aUna historia concreta.Todo el equipo, para todas las historias.
Responde¿Hace lo que el usuario necesitaba?¿Está bien hecha y lista para entregarse?
La defineEl Product Owner con el equipo, por historia.El equipo, de común acuerdo, una vez.
Ejemplo en EventoUAB"Una reserva de más de 4 horas se rechaza.""El código pasó por Pull Request con al menos una revisión."
Una DoD razonable para EventoUAB

Una historia está terminada cuando: (1) cumple todos sus criterios de aceptación; (2) tiene pruebas automáticas para sus casos normales, inválidos y de borde, y pasan; (3) el código fue revisado por al menos otra persona en un Pull Request; (4) está integrada a main sin romper nada; y (5) se probó en el ambiente de pruebas.

La DoD no se negocia historia por historia

Si "revisado" se salta cuando hay apuro, deja de ser parte de la definición de terminado y se vuelve un deseo. Una historia que no cumple la DoD no está terminada: vuelve al tablero, no cuenta para la velocidad del sprint, y es mejor mostrarla así en la Review que mostrarla como completa.

Clasificación

¿Cada condición es un criterio de aceptación de una historia, o un ítem de la Definition of Done del equipo?

Al cancelar una reserva, el espacio vuelve a aparecer libre en el calendario.
Todo el código pasó por revisión en un Pull Request antes de integrarse.
Las pruebas automáticas pasan en la rama principal después de integrar.
Si el club no existe en el sistema, se muestra un mensaje de error claro.
La historia fue desplegada y probada en el ambiente de pruebas del equipo.
Una reserva de más de 4 horas es rechazada con un mensaje que explica el máximo.

Razonamiento

Una historia cumple todos sus criterios de aceptación, pero nadie revisó el código ni lo integró a main. Según la DoD del equipo, ¿en qué estado está?

Ejercicios de razonamiento

En estas preguntas no se te pide recordar una definición: se te da un escenario y debés razonar la respuesta antes de comprobarla.

Escenario

Mateo escribió el criterio de "cancelar una reserva": "Dado que el club tiene una reserva futura, cuando la cancela, entonces el espacio queda libre." Ahora arma sus casos de prueba.

Razonamiento

¿Cuál de estos casos es un caso inválido (y no uno normal ni uno de borde)?

Otro escenario

El equipo tiene 30 pruebas para "reservar un espacio". Al mirarlas, todas son variantes del caso normal: distintos clubes, distintos espacios, distintos horarios, siempre libres y siempre de 1 o 2 horas.

Razonamiento

¿Qué se puede decir del riesgo de que haya errores sin detectar?

Actividades de repaso

Un repaso integrador de todo el módulo. Cada actividad se corrige al instante; tu progreso se guarda automáticamente en este navegador.

0 / 0
actividades correctas en toda la guía
Selección múltiple

¿Por qué los casos de borde suelen encontrar errores que los casos normales dejan pasar?

Verdadero o falso

La Definition of Done es distinta para cada historia y la escribe el Product Owner junto con los criterios de aceptación.

Selección múltiple

¿Qué diferencia hay entre los criterios de aceptación y la Definition of Done?

Selección múltiple

Faltando poco para cerrar el sprint, una prueba automática falla en main. La historia cumple sus criterios y la DoD incluye "las pruebas pasan". ¿Qué corresponde?

Cheat Sheet

TérminoIdea clave
Criterio → pruebaDado = preparar, Cuando = ejecutar, Entonces = comprobar. Cada criterio genera uno o más casos.
Caso normalEl camino feliz: datos correctos y resultado esperado.
Caso inválidoDatos o situaciones que el sistema debe rechazar con un error claro.
Caso de bordeEl valor exacto del límite de una regla (y apenas por encima o por debajo). Detecta errores de comparación.
Criterios de aceptaciónCondiciones de una historia concreta: ¿hace lo que el usuario necesitaba?
Definition of DoneLista común del equipo, aplicada a toda historia: ¿está bien hecha y lista para entregarse? No se negocia por apuro.

¿Sabías que...?

📏 El análisis de valores límite es de los años 70

La técnica de probar justo en los límites de una regla se popularizó con el libro The Art of Software Testing, de Glenford Myers (1979), y sigue siendo una de las más enseñadas en testing.

📘 La DoD está en la Scrum Guide

Scrum define a la Definition of Done como el compromiso del Incremento: si un elemento no la cumple, no puede presentarse en la Sprint Review ni considerarse parte del producto entregado.

🧭 Lo que viene en la próxima guía

Con historias terminadas de verdad, llega el momento de mirar la evidencia: cómo adaptar el backlog a partir de lo que reveló el sprint, y cuándo ayuda (y cuándo estorba) un patrón como Repository con inyección de dependencias.