Playbooks

Testing

Salir

Tipos de test

No todos los tests son iguales. Cada tipo responde una pregunta distinta. Usar el tipo equivocado es como usar un martillo para atornillar: funciona, pero el resultado es frágil.

E2E Pocos
Flujos críticos de negocio. Si falla un E2E, no deployes.
Integración Algunos
Contratos entre módulos. API endpoints, queries, eventos.
Unitarios Muchos
Lógica de negocio pura. Rápidos, aislados, sin IO.
Unitarios ms
Una función o método
Baja — prueba lógica aislada
La base de la pirámide. Sin ellos, todo lo demás es frágil. Cada función pública debe tener al menos un test unitario.
Integración ms–s
Dos o más módulos juntos
Media — prueba que las piezas encajan
Verifican que tu código funciona con dependencias reales: DB, API, filesystem. Sin mocks — querés saber si la query realmente funciona.
End-to-end s–min
El sistema completo
Alta — prueba lo que el usuario ve
Simulan un usuario real. Lentos pero indispensables para flujos críticos: login, checkout, onboarding. No abuses — 5 E2E bien escritos valen más que 50 frágiles.
Snapshot ms
Output de un componente
Baja — detecta cambios no intencionales
Útiles para UI components y serializers. El test falla si el output cambia. Si el cambio es intencional, actualizás el snapshot. Si no, te salvó de un bug.

TDD: Rojo → Verde → Refactor

TDD no es una técnica de testing. Es una técnica de diseño. El test es el primer consumidor de tu API — si es incómodo de testear, es incómodo de usar.

🔴 Rojo
Escribí un test que falle. Solo uno. El test más chico que pruebe algo útil. Si no falla, no estás testeando nada nuevo.
🟢 Verde
Escribí el mínimo código para que el test pase. No refactores, no optimices, no over-engineeres. Solo hacé que pase.
🔵 Refactor
Ahora sí: limpiá, extraé métodos, mejorá nombres. Los tests te dan la red de seguridad para mover código sin miedo.
1. Nunca escribas código de producción sin un test que falle primero. Es la regla de oro.
2. El ciclo rojo-verde-refactor debe durar minutos, no horas. Si tardás más, el test es muy grande.
3. TDD no es solo testing — es diseño. Te obliga a pensar en la interfaz antes que en la implementación.
4. Si testear algo es difícil, tu diseño está mal. Acoplamiento alto = tests imposibles.
5. No todos los proyectos justifican TDD puro. Pero todo proyecto justifica tests.

Buenas prácticas

Un test mal escrito es peor que ningún test — da falsa confianza y hace perder tiempo cuando falla por razones equivocadas.

Nombres que explican el escenario
✅ should_return_422_when_email_is_missing() ❌ test_validation_1()
Estructura AAA: Arrange, Act, Assert
✅ // Arrange const user = buildUser() // Act const result = validate(user) // Assert expect(result.error).toBe("email required") ❌ // Todo mezclado const r = validate(buildUser()) expect(r.error).toBeTruthy()
Un concepto por test
✅ test("retorna 422 si falta email") test("retorna 422 si email es inválido") ❌ test("validación de email funciona")
No testees implementación, testea comportamiento
✅ expect(service.getTotal(cart)).toBe(150) ❌ expect(service.calculateTax).toHaveBeenCalledTimes(1)
Fixtures compartidas, no herencia
✅ beforeEach(() => { user = await createTestUser() }) ❌ class UserTest extends BaseTest { ... }
Mocks solo para IO externa
✅ mockEmailService.send = jest.fn() ❌ mockUserRepository.save = jest.fn() // esto es integración, no unit

Anti-patrones

❌ Test que pasa siempre (false positive)
✅ Si tu test no puede fallar, no está testeando nada. Forzalo a fallar primero.
❌ Test flaky (a veces pasa, a veces no)
✅ Causa #1: dependencia de tiempo/orden/red. Usá fake timers, seeds determinísticas, y mocks de red.
❌ Test que testea el mock, no el código
✅ Si mockeás el 80% de las dependencias, no estás testeando integración real.
❌ Cobertura 100% como meta
✅ El 100% es un espejismo. Cuesta el doble que 80% y no agrega el doble de seguridad. Perseguí confianza, no porcentajes.

CI & Coverage

Si los tests no corren en CI, no existen. El pipeline es el guardián que impide que el código roto llegue a producción.

1
Lint ESLint / Biome
Estilo y errores obvios. No debería tomar más de 30 segundos.
2
Type check TypeScript / tsc
Si el tipo no compila, no llegás a tests. Cero tolerancia a errores de tipo.
3
Unit tests Vitest / Jest
Deben correr en < 2 minutos. Si tardan más, paralelizá o revisá qué estás testeando.
4
Integration tests Vitest / Playwright
Contra una DB de prueba. Testcontainers o Docker compose para levantar dependencias.
5
Coverage check c8 / istanbul
Mínimo 80% en líneas, 70% en branches. No es un número mágico — es un piso de seguridad.
6
E2E (critical paths) Playwright / Cypress
Solo los flows de negocio que no pueden fallar. Paralelizá para que no bloquee el pipeline.

Coverage targets

Líneas ≥ 80% El mínimo viable. Si no ejecutás una línea en tests, no sabés si funciona.
Branches ≥ 70% Cada if/else, cada switch, cada try/catch debe tener ambos caminos testeados.
Funciones ≥ 85% Si una función no se llama en tests, probablemente es código muerto.