Glossário · Fundamentos de testes
Test double (dublê de teste)
Em inglês: Test double
Também chamado de: dublê de teste, test doubles, dublês de teste, mock
Definição
Qualquer objeto que substitui uma dependência real em um teste, como dummy, stub, fake, spy ou mock, para que o código sob teste rode de forma rápida e previsível.
Um test double (dublê de teste) substitui uma dependência real, como um gateway de pagamento, um banco de dados, um relógio ou um serviço de e-mail, por algo que o teste controla. O nome, popularizado por Gerard Meszaros, vem do dublê dos filmes. Os dublês deixam os testes rápidos e determinísticos e permitem simular situações difíceis de produzir de verdade, como um timeout ou um cartão recusado.
Os cinco tipos
| Tipo | O que faz | Exemplo |
|---|---|---|
| Dummy | Passado apenas para preencher um parâmetro, nunca é usado | Um null ou um logger vazio que o método exige, mas que este teste nunca toca |
| Stub | Retorna respostas prontas para as chamadas | rates.getRate("EUR") sempre retorna 0.92 |
| Spy | Um stub que também registra como foi chamado | Registra que send() foi chamado uma vez com um determinado endereço |
| Mock | Pré-programado com expectativas, e o teste verifica as interações | Verificar que gateway.charge(4999) foi chamado exatamente uma vez |
| Fake | Uma implementação funcional, mas simplificada | Um repositório em memória apoiado em um HashMap |
No dia a dia, “mock” é usado para todos eles, e bibliotecas como o Mockito criam objetos que podem agir como stubs, spies ou mocks. Mesmo assim, conhecer a distinção ajuda, principalmente stub vs mock: um stub fornece entradas para o código sob teste (verificação de estado), enquanto um mock verifica as saídas que o código envia às suas dependências (verificação de comportamento).
Exemplo (JUnit 5 com Mockito)
@Test
void declinedCardDoesNotSendConfirmation() {
PaymentGateway gateway = mock(PaymentGateway.class);
EmailService email = mock(EmailService.class);
when(gateway.charge(4999)).thenReturn(PaymentResult.DECLINED); // stub
var checkout = new Checkout(gateway, email);
var result = checkout.placeOrder(4999);
assertEquals(OrderStatus.PAYMENT_FAILED, result.status());
verify(email, never()).sendConfirmation(any()); // mock-style verification
}
(Os imports estáticos de org.mockito.Mockito, org.mockito.ArgumentMatchers e org.junit.jupiter.api.Assertions foram omitidos.)
Erros comuns
- Mockar tudo. Testes que verificam cada chamada interna quebram a cada refatoração e podem passar enquanto a integração real está quebrada. Use mocks nas fronteiras da arquitetura; dentro delas, prefira objetos reais ou fakes.
- Dublês que se afastam da realidade. Uma API em stub que retorna um campo que o serviço real renomeou meses atrás dá uma falsa confiança. Testes de contrato e alguns testes de integração reais mantêm os dublês honestos.
- Mockar tipos que não são seus. Encapsule clientes de terceiros em uma interface própria e crie o dublê dessa interface.