Testabilidade e Arquitetura
A tese central
Seção intitulada “A tese central”Se testar uma classe é difícil, o problema quase nunca é o teste — é o design. Código difícil de testar é código acoplado a detalhes concretos (banco, relógio, rede, framework). O mesmo DIP que faz o domínio depender de abstrações também torna essas dependências substituíveis por dublês no teste. Ou seja: arquitetura e testabilidade são a mesma moeda vista de dois lados.
graph LR
subgraph Produção
UC1["Caso de uso"] --> P1["Porta ContaRepository"]
P1 -.implementada por.-> A1["ContaJpaAdapter"]
end
subgraph Teste
UC2["Caso de uso"] --> P2["Porta ContaRepository"]
P2 -.implementada por.-> A2["InMemoryContaRepository (Fake)"]
end
O caso de uso não muda entre produção e teste. Só troca o adapter que satisfaz a porta. Essa é a essência de por que Hexagonal/Clean são tão testáveis.
Dublê de teste = adapter de teste
Seção intitulada “Dublê de teste = adapter de teste”A taxonomia de dublês (Test Doubles - Stub, Spy, Mock e Fake) mapeia diretamente nos conceitos de arquitetura:
| Conceito de teste | Conceito de arquitetura |
|---|---|
| A dependência que você substitui | Uma driven port (ex: repositório, gateway) |
Fake (ex: InMemoryRepository) |
Um adapter secundário de teste, feito à mão |
| Stub (respostas canned) | Adapter mínimo que devolve estado fixo |
| Mock (verifica interação) | Verificação de que o núcleo chamou a porta corretamente |
| O que você testa “por dentro” | O núcleo: Entidades, Value Objects, Use Cases |
O que testar em cada anel
Seção intitulada “O que testar em cada anel”A arquitetura também diz que tipo de teste cabe onde — conectando a pirâmide de testes às camadas:
| Elemento | Tipo de teste ideal | Por quê |
|---|---|---|
| Value Objects, Entidades, Agregados | Unit puro, sem mocks | São lógica pura; invariantes se testam com asserts diretos |
| Use Cases / serviços de aplicação | Unit com Fakes nas portas | Orquestração testada rápido, sem infraestrutura |
| Adapters secundários (JPA, HTTP) | Integração (Testcontainers) | O que importa é a fidelidade à tecnologia real |
| Fluxo ponta a ponta | E2E (poucos) | Confiança de que os anéis se encaixam |
Repare que o domínio rico do DDD é o mais barato de testar: lógica sem dependências. Entidades anêmicas empurram essa lógica para services cheios de mocks — um cheiro que Code Smells e SOLID detalha.
TDD fecha o ciclo
Seção intitulada “TDD fecha o ciclo”Não é coincidência que TDD produza designs parecidos com Hexagonal/Clean: escrever o teste primeiro te obriga a inventar a abstração (a porta) antes do detalhe. O teste é o primeiro cliente do seu núcleo, e ele reclama na hora se você acoplar infraestrutura cedo demais. TDD é, na prática, inversão de dependência guiada por pressão de teste.
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Mockar o que você possui vs o que não controla: criar mock de um value object ou de uma entidade é sinal de over-mocking. Dublês são para portas (fronteiras), não para lógica pura.
- Testar o adapter com mock do driver: mockar o
EntityManager/JDBC testa a sua imaginação, não a integração. Adapter se testa contra a tecnologia real (Testcontainers). - Vazar tipos de framework para dentro do teste de domínio: se o teste da entidade precisa de
@SpringBootTest, a regra da dependência foi violada. - “Preciso de mock para tudo”: excesso de mocks costuma denunciar acoplamento alto — o design, não o teste, é o problema.
Relações
Seção intitulada “Relações”- Test Doubles - Stub, Spy, Mock e Fake
- Ports · Adapters · DIP - Dependency Inversion Principle
- Tipos de Teste - Unit, Integration e E2E
- Test-Driven Development
- Arquitetura Hexagonal · Clean Architecture
- Code Smells e SOLID
- Como Tudo se Conecta
Perguntas de revisão
Seção intitulada “Perguntas de revisão”- Por que se diz que um Fake é um adapter, e não apenas “código de teste”?
Resposta
Porque ele implementa a mesma porta (interface) que o adapter de produção. Do ponto de vista do núcleo, é indistinguível de qualquer outro adapter secundário — só vive no código de teste e guarda estado em memória.
- Qual mecanismo comum explica tanto a testabilidade quanto a arquitetura Hexagonal/Clean?
Resposta
A inversão de dependência (DIP): o núcleo depende de abstrações, então qualquer implementação (real ou dublê) pode ser plugada na porta.
- Se testar um serviço exige mockar cinco colaboradores, o que isso provavelmente indica?
Resposta
Acoplamento alto e/ou responsabilidades demais (violação de SRP). O sintoma aparece no teste, mas a causa é de design. Ver Code Smells e SOLID.
- Por que entidades e value objects são os elementos mais baratos de testar?
Resposta
São lógica pura, sem dependências de infraestrutura. Testam-se com asserts diretos sobre invariantes, sem mocks nem contexto de framework.