/unit-testing diseña y escribe tests de una unidad: una función, una clase, un módulo. Cubre el ciclo red-green-refactor, cómo nombrar cada test, qué mockear y qué cobertura mirar. Corre sola, sobre el código que le señales, o a mitad de una historia, cuando /sprint-development encuentra un tramo que conviene hacer test-first.
Su interfaz pública es el contrato que los tests fijan.
El más chico posible, y falla por la aserción, no por un import roto.
Lo justo para pasar. La implementación real emerge en varios ciclos.
Con los tests como red de seguridad. Nunca con un test en rojo.
Es una skill acotada a propósito: no lleva Jira, no despliega, no hace code review. Produce código testeado para un tramo y devuelve el control.
Entras sola o desde una historia en curso. Lo que pides elige la referencia que la IA lee; cuando no está claro, arranca por la guía general.
Es el orden canónico para una IA que arranca en frío. Corta antes cuando lo que sigue no aporta nada para el tramo.
Primero su interfaz pública: es el contrato que los tests tienen que fijar.
Los *.test.ts o *.spec.ts de la misma carpeta. Se extienden, no se duplican.
Buscar el símbolo dice qué colaboradores son externos (se mockean) y cuáles internos (se usan reales).
vitest.config.ts, jest.config.ts o equivalente: variables, archivos de setup, umbrales de cobertura, alias de rutas.
Se reusan las costuras del proyecto en lugar de inventar otras paralelas.
Sin /sprint-development de por medio, trabaja contra el código que le indiques y se arregla sola con lo que encuentre.
Identifica la unidad y decide si va test-first o después. Escribe los tests con la convención de nombres del proyecto y mockea solo las dependencias externas.
Corre la suite hasta verde y mide la cobertura de esa unidad.
Qué unidad, cuando el pedido es ambiguo: la IA te lo confirma antes de escribir.
El runner, solo si stack.test_runner es null: la IA te pregunta y la elección se guarda con bun run agents:setup --stack.
Archivos de test junto al código, con el mismo nombre más .test.ts.
Un reporte: archivos agregados, tests que pasan y el delta de cobertura.
En /sprint-development, el Stage 2 (implementación) marca el TDD como opcional. Cuando un tramo lo amerita, delega en esta skill y retoma cuando la unidad quedó en verde.
Una función de lógica pura.
Ramas complejas con casos borde: mejor fijarlos con tests que adivinarlos después.
Un bug: primero el test que lo reproduce y falla, después el arreglo.
No mueve el ticket en Jira, no abre el PR, no hace review ni deploy.
Todo eso sigue siendo de /sprint-development. El límite entre las dos skills es informal y las dos lo conocen.
El tramo en verde y refactorizado.
El Stage 2 sigue con su verificación en paralelo: lint, tipos y unit tests, y vuelve a iterar si algo queda en rojo.
| Si pides… | Entra por |
|---|---|
| "Escribe unit tests para esta función, TDD" | /unit-testing directo: un pedido de tests saltea al orquestador. |
| "Implementa esta historia: código, tests y PR" | /sprint-development. Puede llamar a /unit-testing por dentro, pero la entrada es el orquestador. |
Test antes del código, en ciclos de cinco a diez minutos. Si un ciclo pasa de media hora, el tramo es demasiado grande: se parte en pasos de comportamiento más chicos.
El test más chico que captura un pedazo de comportamiento. Tiene que fallar por la aserción; uno que falla porque el archivo no compila no informa nada. Si pasa en la primera corrida, algo huele mal: se investiga antes de seguir.
Lo más simple que lo pase. Un valor fijo vale en esta etapa. Nada de código para tests que todavía no existen.
Extraer, renombrar, deduplicar, con los tests vigilando. Refactorizar en rojo es perder la red de seguridad justo cuando más hace falta.
| Tipo de código | Test-first o después? |
|---|---|
| Lógica de negocio, funciones puras | TDD, muy recomendado |
| Algoritmos, parsers, máquinas de estado, validaciones | TDD |
| Corrección de un bug | TDD: el test que reproduce el bug va primero |
| Código crítico en rendimiento | TDD, con benchmarks junto a las aserciones |
| Componentes de UI presentacionales | Después (o tests de componente, que a menudo se saltean) |
| Pegamento de integración (wrappers de DB, clientes de API) | Después; lo cubren mejor los tests de integración |
| Scripts descartables, migraciones de una vez | Se saltea |
regla práctica: si tiene ramas, cuentas o parsing de strings, va con TDD; si casi solo orquesta otras cosas, el test va después o lo cubre un nivel más alto
El nombre de un test es lo que ves cuando falla, casi siempre en un log de CI y meses después. Si no se puede nombrar en pocas palabras, el test hace demasiado.
describe('cart with items', () => { it('returns total including tax when item added', () => { ... }); it('returns 0 when all items removed', () => { ... }); }); describe('cart with no items', () => { it('throws when attempting checkout', () => { ... }); });
| Mal | Bien |
|---|---|
| testGetUser | returnsUserWhenIdExists |
| testError | throwsValidationErrorOnEmptyEmail |
| testBoundary | appliesDiscountAtExactly100Threshold |
| callsApiOnce | un nombre de comportamiento, no de interacción con el mock |
cuando la misma regla vale para muchas entradas, se parametriza y se nombra la regla, no cada caso
Un test que mockea todos los colaboradores verifica el grafo de mocks, no el código. Las implementaciones reales van por defecto; el mock queda para lo que hace al test lento, frágil o no determinista.
| Herramienta | Para qué |
|---|---|
| Stub | Reemplaza la implementación por un retorno fijo. |
| Spy | Envuelve la implementación real y observa las llamadas sin cambiar el comportamiento. |
| Fake | Una implementación que funciona pero simplificada: una base en memoria, un reloj falso. |
| Mock | Expectativa programada que falla si no se la llama como se esperaba. Tiende a atar el test a la implementación: se prefieren spies y stubs. |
// service.ts: la dependencia entra como argumento export async function getUser(id: string, db = defaultDb) { return db.users.findOne({ id }); } // service.test.ts: un fake, sin jest.mock it('returns the user', async () => { const fakeDb = { users: { findOne: async () => ({ id: '1', name: 'A' }) } }; expect(await getUser('1', fakeDb)).toEqual({ id: '1', name: 'A' }); });
Cobertura baja significa tests que faltan. Cobertura alta no significa tests buenos: un test que llama la función y no afirma nada también suma líneas. Lo útil es el delta de cada PR, no el número global.
| Tipo de código | Cobertura sugerida |
|---|---|
| Lógica de negocio, funciones puras | 90-100% |
| Métodos de API pública | 90% o más |
| Helpers internos | 70-90% |
| Componentes de UI presentacionales | 60-80% (el resto lo cubre E2E) |
| Pegamento, configuración, wiring | 50% o más, o se saltea |
| Código generado, scripts descartables | se excluye |
son guías, no contratos: un helper al 70% que ejercita cada rama importante vale más que uno al 95% cuyo 5% faltante es el único camino de error
Los antipatrones completos viven en SKILL.md y viajan en el registro compacto que reciben los subagentes (.agents/skills/REGISTRY.md).
Esta skill no tiene modos con nombre: lo que pides elige la referencia. Nombras la skill y describes el tramo, en español o en inglés.
La barra carga la skill; el resto de la frase elige el tema.
Sin barra: nombras la skill en la frase.
Mismo patrón que OpenCode, CLI o Desktop.
| Si dices algo como… | La IA lee |
|---|---|
| "TDD this function" · "red-green-refactor" · "test before code" | tdd-workflow.md |
| "name this test" · "AAA" · "Given-When-Then" | test-naming.md |
| "qué mockear" · "Vitest spy" · "DI for testing" | mocking-patterns.md |
| "coverage target" · "mutation testing" | test-coverage.md |
| principios generales · setup del runner | unit-testing.md |
las referencias viven en .agents/skills/unit-testing/references/ · ante la duda, la IA arranca por unit-testing.md, que apunta a las demás
Llama a esta skill en el Stage 2 para un tramo TDD o el reproductor de un bug, y retoma cuando la unidad está en verde y refactorizada.
Monta el repo y deja los tests unitarios como tema aparte, para correr en cualquier momento después. Deck: Project bootstrap.
Para lo end-to-end contra la app corriendo. El diseño de tests de integración y E2E pertenece a un flujo de QA aparte.
Los tests viajan en el mismo commit que el comportamiento que verifican, no en un commit test: aparte.