Arquitetura software
TDD na Pratica: Next.js e Spring Boot
Test-Driven Development (TDD) e a disciplina de escrever teste antes do codigo de producao, com ciclos curtos de feedback.
Ciclo Red-Green-Refactor
- Red: escreva um teste que falha.
- Green: implemente o minimo para passar.
- Refactor: melhore design sem quebrar teste.
TDD e mais sobre design incremental do que sobre "ter muitos testes".
Exemplo simples de regra (TypeScript)
import { describe, it, expect } from "vitest"
import { calculateDiscount } from "./calculate-discount"
describe("calculateDiscount", () => {
it("aplica 15% para cliente VIP", () => {
expect(calculateDiscount("VIP", 200)).toBe(170)
})
})export function calculateDiscount(customerType: string, amount: number) {
if (customerType === "VIP") return amount * 0.85
return amount
}TDD em Next.js
Abordagem recomendada:
- testar primeiro
domaineapplication; - usar integration tests em route handlers;
- evitar iniciar com E2E quando a regra ainda esta mudando.
Exemplo de use case com porta:
export interface OrderRepository {
save(order: { id: string; amount: number }): Promise<void>
}
export class CreateOrderUseCase {
constructor(private readonly orders: OrderRepository) {}
async execute(input: { id: string; amount: number }) {
if (input.amount <= 0) throw new Error("Invalid amount")
await this.orders.save(input)
return { id: input.id }
}
}Teste:
it("falha para amount invalido", async () => {
const repo: OrderRepository = { save: async () => {} }
const useCase = new CreateOrderUseCase(repo)
await expect(useCase.execute({ id: "1", amount: 0 })).rejects.toThrow("Invalid amount")
})TDD em Spring Boot
Abordagem:
- JUnit 5 para unidade;
- Mockito para doubles de porta;
- SpringBootTest para integracao seletiva.
class CreateOrderUseCaseTest {
@Test
void shouldFailWhenAmountIsInvalid() {
OrderRepositoryPort repo = Mockito.mock(OrderRepositoryPort.class);
CreateOrderUseCase useCase = new CreateOrderUseCase(repo);
assertThrows(IllegalArgumentException.class,
() -> useCase.execute(new CreateOrderInput("1", BigDecimal.ZERO)));
}
}Estrutura de suite recomendada
unit: dominio, value objects, use cases.contract: adaptadores (DB/API/fila) com contrato esperado.integration: fluxo de persistencia e HTTP.e2e: poucas jornadas criticas.
Distribuicao pragmatica:
- 60% unidade
- 30% integracao/contrato
- 10% e2e
Armadilhas comuns
- Testar implementacao interna em vez de comportamento.
- Mockar tudo e perder confianca no teste.
- Testes lentos demais no ciclo local.
- Ignorar refatoracao depois do green.
- Acoplar teste a framework em vez de regra.
Checklist de qualidade de testes
- O nome do teste expressa regra de negocio?
- Teste passa sem depender de clock/rede real?
- Setup esta minimo e claro?
- Falha do teste indica causa precisa?
- Refatoracao manteve suite verde?
Recursos recomendados
YouTube
Artigos e documentacao
- Test Driven Development by Example (Kent Beck)
- Martin Fowler - Mocks Aren't Stubs
- JUnit 5 User Guide
- Vitest Guide
- Spring Testing
Papers e evidencias
- On the Effectiveness of Test-first Approach (IEEE)
- A Controlled Experiment of TDD in Industry
- Realizing quality improvement through TDD (Empirical Software Engineering)
Livros
- Test Driven Development: By Example - Kent Beck
- Growing Object-Oriented Software, Guided by Tests
- xUnit Test Patterns - Gerard Meszaros
Posts no X (opcional)
Conclusao
TDD cria feedback rapido e puxa design para baixo acoplamento. Em Next.js e Spring Boot, o maior ganho aparece quando as regras ficam em camadas testaveis antes de qualquer detalhe de framework.