Testing en Clean Architecture
La arquitectura limpia facilita testing porque separa comportamiento de detalles.
La pregunta clave es: ¿qué quiero demostrar en esta capa?
Dominio
Prueba reglas puras.
No debería haber mocks, base de datos, red ni framework.
it("marks an invoice as overdue after its due date", () => {
const invoice = new Invoice({
dueDate: new Date("2026-01-10"),
paidAt: null,
});
expect(invoice.isOverdue(new Date("2026-01-11"))).toBe(true);
});Application
Prueba casos de uso.
Aquí interesa verificar comportamiento completo de una operación, pero sustituyendo los límites externos por fakes o repositorios in-memory.
it("creates a task in the requested project", async () => {
const tasks = new InMemoryTaskRepository();
const projects = new InMemoryProjectRepository([
{ id: "project-1", name: "Website" },
]);
const createTask = createTaskUseCase({ tasks, projects });
await createTask({
projectId: "project-1",
title: "Prepare deploy",
});
expect(await tasks.findByProjectId("project-1")).toHaveLength(1);
});Interface Adapters
Prueba validación, mapping y formato de salida.
No hace falta volver a probar toda la lógica del caso de uso. Para eso ya están los tests de application.
it("returns a validation error when title is empty", async () => {
const result = await createTaskController({
body: { title: "" },
});
expect(result.status).toBe(400);
});Infrastructure
Prueba adapters reales con tests de integración.
Ejemplos:
- Un repositorio guarda y recupera correctamente.
- Un cliente HTTP interpreta errores externos.
- Un adapter de filesystem maneja rutas inexistentes.
Estos tests pueden necesitar base de datos de test, contenedores o fixtures.
Presentation
Prueba solo lo que pertenece a la UI:
- Estados visibles.
- Interacción del usuario.
- Mensajes de error.
- Navegación.
- Flujos críticos.
La UI no debería ser el único sitio donde se prueban reglas de negocio.
Estrategia recomendada
- Muchos tests unitarios de dominio y casos de uso.
- Algunos tests de integración para adapters importantes.
- Pocos E2E para flujos críticos.
- Tests de regresión para bugs reales.
Señales de mal diseño
- Para testear una regla de negocio hay que renderizar React.
- Para probar un caso de uso hay que conectar una base de datos real.
- Los tests fallan si cambia el texto interno de una implementación.
- Casi todos los tests verifican llamadas a mocks.
- La lógica está repartida entre controllers, componentes y repositorios.