🕵️ 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

TipoComportamento PadrãoUso Recomendado
MockResponde null, 0 ou false para tudo.Isolamento Total de Dependências.
SpyExecuta 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 de when(...).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. 🏁


⬅️ Capítulo Anterior | Próximo Capítulo ➡️