🕵️ 3.11 Dublês Parciais: O Poder do @Spy
Existem situações onde não queremos simular o objeto inteiro (Mock), mas sim manter o comportamento real de 90% da classe e interceptar apenas um ou dois métodos específicos. Para isso, utilizamos o Spy (Espião).
🏗️ Mock vs Spy
| Tipo | Comportamento Padrão | Uso Recomendado |
|---|---|---|
| Mock | Responde null, 0 ou false para tudo. | Isolamento Total de Dependências. |
| Spy | Executa o código real dos métodos. | Teste de Classes Legadas ou “Mocks Parciais”. |
📄 Exemplo: Espionando uma Regra Interna
Imagine que você quer testar a classe Calculador mas precisa forçar o resultado de um método auxiliar complexo sem criar uma nova classe.
@Test
void deveEspionarMetodoEspecifico() {
// 1. Criar um espião sobre uma instância real
List<String> list = new ArrayList<>();
List<String> spyList = spy(list);
// 2. Forçar comportamento em um método específico
doReturn(100).when(spyList).size();
// 3. O resto da lista continua real!
spyList.add("Item 1");
assertThat(spyList.get(0)).isEqualTo("Item 1"); // Real
assertThat(spyList.size()).isEqualTo(100); // Espionado
}Use com Extrema Cautela 🛡️
O uso de Spies é frequentemente um “Code Smell” (sinal de código problemático). Se você precisa espionar métodos da classe que está testando, provavelmente sua classe tem Responsabilidades Demais e deveria ser dividida.
⚡ Quando o Spy é Útil (Elite Use Case)
- Refatoração de Legado: Quando a classe é um “Objeto Gigante” (God Object) e você não pode quebrá-la agora, o Spy permite isolar partes ruidosas para validar a nova lógica.
- APIs de Terceiros Sem Interfaces: Quando você herda classes concretas de frameworks que não permitem Mocking total.
Sintaxe de Spy 🚀
Ao usar Spies, prefira
doReturn(...).when(spy).metodo()em vez dewhen(...).thenReturn(). A segunda forma executa o método real antes de stubbar, o que pode causar erros se o método real for pesado ou lançar exceções. 🏁