ATDD invierte el orden habitual: QA escribe un test de aceptación en Playwright antes de que exista la funcionalidad, el test falla, y la funcionalidad está terminada cuando el test pasa. Ese único cambio mueve a QA de verificar trabajo terminado a definir qué significa "terminado". Este artículo cubre el ciclo Rojo-Verde-Refactor, cómo el formato Given/When/Then de BDD encaja en el flujo de trabajo de los tres amigos, y qué cambia en el día a día de QA cuando los desarrolladores ya practican TDD.

El ciclo TDD: Rojo, Verde, Refactor

TDD sigue un ciclo estricto de tres pasos:

1. Rojo: escribir un test que falle (porque la funcionalidad todavía no existe)

2. Verde: escribir el código mínimo para que el test pase

3. Refactor: limpiar el código manteniendo los tests en verde

Este ciclo se repite para cada pequeña pieza de funcionalidad.

// Fase rojo: escribir un test que falle
test('calculateDiscount aplica 10% para el código SAVE10', () => {
  const result = calculateDiscount(100, 'SAVE10');
  expect(result).toBe(90);
});

// Ejecutar este test falla: calculateDiscount no está definida

// Fase verde: escribir el código mínimo para pasar
function calculateDiscount(price: number, code: string): number {
  if (code === 'SAVE10') {
    return price * 0.9;
  }
  return price;
}

// Ahora el test pasa

// Fase refactor: limpiar sin romper el test
const DISCOUNT_CODES: Record<string, number> = {
  SAVE10: 0.1,
  SAVE20: 0.2,
  SAVE50: 0.5,
};

function calculateDiscount(price: number, code: string): number {
  const discount = DISCOUNT_CODES[code] || 0;
  return price * (1 - discount);
}

// Los tests siguen pasando: el refactor no rompió nada

Beneficios de TDD que afectan a QA

Código naturalmente testeable

El código escrito con TDD tiende a tener funciones más pequeñas con entradas y salidas claras, más fácil de probar a todos los niveles.

Seguridad ante regresiones

Cada comportamiento está protegido por un test. Cuando QA encuentra un bug, los desarrolladores pueden reproducirlo con un test, corregirlo, y el test previene regresiones.

Documentación a través de tests

Los tests TDD describen qué debería hacer el código en escenarios específicos. QA puede leer los tests para entender el comportamiento esperado.

Detección temprana de bugs

Los problemas detectados al escribir tests unitarios son órdenes de magnitud más baratos de corregir que los encontrados en QA o en producción.

Desarrollo guiado por comportamiento (BDD)

BDD extiende TDD hacia la capa de negocio. Donde TDD se enfoca en cómo funciona el código, BDD se enfoca en qué comportamiento se requiere.

Los tres amigos: desarrollador, QA y product manager colaboran para definir comportamientos usando el formato Given/When/Then antes de escribir cualquier código.

Feature: Códigos de descuento

  Scenario: Un código de descuento válido reduce el precio
    Given tengo un carrito con artículos por un total de $100
    When aplico el código de descuento "SAVE10"
    Then el total debería ser $90
    And el monto de descuento debería ser $10

  Scenario: Un código de descuento inválido muestra error
    Given tengo un carrito con artículos por un total de $100
    When aplico el código de descuento "INVALID"
    Then debería ver "Código de descuento inválido"
    And el total debería seguir siendo $100

  Scenario: Un código de descuento vencido muestra error
    Given tengo un carrito con artículos por un total de $100
    When aplico el código de descuento "EXPIRED20"
    Then debería ver "Este código de descuento ha vencido"

Cómo QA puede aplicar la mentalidad TDD

Aunque no estés escribiendo tests unitarios, puedes aplicar la mentalidad TDD.

Escribir casos de prueba antes de que empiece el testing manual

En lugar de hacer testing exploratorio desde cero, escribe primero los comportamientos esperados:

Funcionalidad: Reseteo de contraseña

Lo que espero que sea verdad:
1. Ingresar un email válido envía un email de reseteo en 2 minutos
2. Ingresar un email inválido muestra "Email no encontrado"
3. El enlace de reseteo vence después de 24 horas
4. Usar un enlace vencido muestra "Enlace vencido" con opción de solicitar uno nuevo
5. Después de un reseteo exitoso, la contraseña anterior ya no funciona
6. El enlace de reseteo solo puede usarse una vez

Ya tienes un plan de pruebas antes de empezar a probar.

Desarrollo guiado por tests de aceptación (ATDD)

Colabora con los desarrolladores para escribir tests de aceptación antes de que se construya la funcionalidad:

// Escrito antes de que exista la funcionalidad
test('el checkout con tarjeta válida completa la compra', async ({ page }) => {
  // Configuración: usuario con artículos en el carrito
  // ...

  // Ejecutar checkout
  await page.fill('[data-testid="card-number"]', '4242 4242 4242 4242');
  await page.fill('[data-testid="card-expiry"]', '12/28');
  await page.fill('[data-testid="card-cvc"]', '123');
  await page.click('[data-testid="pay-now"]');
  
  // Resultados esperados
  await expect(page).toHaveURL('/order-confirmation');
  await expect(page.getByTestId('order-number')).toBeVisible();
  await expect(page.getByTestId('success-message')).toContainText('Pago exitoso');
});

Estos tests fallan hasta que se construye la funcionalidad. Cuando pasan, la funcionalidad está terminada.

Cuando los desarrolladores practican TDD: qué necesita saber QA

Qué cambia para QA

#### La cobertura de tests unitarios ya existe

Los desarrolladores ya probaron los casos extremos a nivel de código. QA puede enfocarse en los puntos de integración, los flujos de usuario y la lógica de negocio, no en el comportamiento básico de las funciones.

#### Los fallos de tests son significativos

Cuando el CI de un equipo TDD falla, es específico. "La función X devuelve un valor incorrecto para el caso extremo Y", no "la app está rota en algún lugar".

#### El refactor es más seguro

Con tests unitarios completos, QA no necesita volver a probar funcionalidad básica después de un refactor: los tests ya la cubren.

Lo que QA todavía necesita hacer

#### Testing de integración

Los tests unitarios prueban funciones en aislamiento. QA prueba cómo trabajan juntos los componentes: la base de datos, la API, el frontend, el sistema de email.

#### Testing desde la perspectiva del usuario

Los desarrolladores prueban "¿funciona el código?". QA prueba "¿tiene sentido usar esta funcionalidad?".

#### Descubrimiento de casos extremos

El testing exploratorio de QA encuentra escenarios que no se especificaron. TDD solo cubre lo que se pensó al escribir los tests.

#### Rendimiento y confiabilidad

TDD no cubre tiempos de respuesta, usuarios concurrentes ni qué pasa bajo carga.

TDD práctico para automatización de tests

Al construir tu framework de tests, aplica los principios TDD:

// En lugar de escribir el helper completo primero, escribí un test para lo que querés que haga
test('el helper de login debería redirigir al dashboard después del login', async ({ page }) => {
  await loginAs(page, 'member');  // Esta función todavía no existe
  
  await expect(page).toHaveURL('/dashboard');
});

// Ahora escribí la implementación mínima
async function loginAs(page: Page, role: 'admin' | 'member') {
  const credentials = {
    admin: { email: 'admin@test.com', password: 'AdminPass1' },
    member: { email: 'member@test.com', password: 'MemberPass1' },
  };
  
  await page.goto('/login');
  await page.fill('[data-testid="email"]', credentials[role].email);
  await page.fill('[data-testid="password"]', credentials[role].password);
  await page.click('[data-testid="submit"]');
  await page.waitForURL('/dashboard');
}

Esto previene el sobreingeniering. Construyes exactamente lo que se necesita, y el test confirma que funciona.

La pirámide de testing en el contexto TDD

TDD da forma directamente a la pirámide de testing:

         /\
        /E2E\          ← Automatización QA (pocos, lentos)
       /------\
      / Integr.\       ← Tests de integración (moderados)
     /----------\
    / Tests Unit.\     ← Output de TDD (muchos, rápidos)
   /--------------\

TDD produce la base amplia de tests unitarios. QA construye las capas de integración y E2E encima. Juntas forman una pirámide donde la mayoría de los bugs se detectan barato a nivel unitario, con un conjunto pequeño y enfocado de tests E2E costosos.

→ See also: Desarrollo Guiado por Tests: La Guía del Ingeniero QA | Testing Shift-Left: Qué Significa y Cómo Practicarlo | La Pirámide de Tests Explicada para Ingenieros QA