Verificação de chamada TDD Mock - é um anti-padrão?

11

Estou fazendo TDD há um ano, me sinto muito bem com isso, amo minhas suítes de teste e tudo mais. No entanto, notei que ultimamente tenho feito muita verificação de chamadas falsas. Por exemplo, eu teria um Serviço que terá um Repositório injetado - no meu teste de unidade, passaria uma simulação do Repositório e verificaria se ele foi chamado dentro do método que estou testando. Eu verificaria se os resultados retornados estão corretos (em outro teste). Definitivamente, isso "parece" errado, pois meus testes de unidade agora estão muito acoplados aos detalhes da implementação. Ouvi dizer que você deveria testar o "comportamento", no entanto, em muitas situações que ... emm - não é possível? Se você tem umvoidPor exemplo, você costuma testar efeitos colaterais. Quero dizer, é fácil seguir em frente e mostrar alguns códigos-katas simples, onde isso pode ser demonstrado, mas IMHO não reflete muito bem os programas do mundo real que escrevemos. O que estou fazendo de errado? Esse tipo de teste é um anti-padrão? Eu apreciaria sua opinião sobre isso, ainda sou um pouco novato no que diz respeito ao TDD.

Dimitar Dimitrov
fonte
2
Resposta curta: sim. Já existem perguntas muito interessantes sobre esse tópico em algum lugar aqui. Seus testes de unidade não devem ser frágeis e dependem muito da sua implementação. É por isso que os testes de nível superior são para (integração etc.). Aqui: programmers.stackexchange.com/questions/198453/…
Kemoda
@Kemoda Eu apreciaria se você pudesse me vincular a uma discussão ou a algum material adicional sobre isso, gostaria muito de melhorar minhas técnicas.
Dimitar Dimitrov
1
você tem isso, por exemplo, programmers.stackexchange.com/questions/198453/... i vai encontrar outros links mais tarde
Kemoda

Respostas:

8

Bem, você deve tentar testar entradas e saídas. Você deve verificar o comportamento visível externamente. As "promessas" ou "contratos" que sua turma faz.

Ao mesmo tempo, às vezes não há maneira melhor de testar um método do que fazer o que você disse.

Eu acho que isso torna seu teste mais frágil; portanto, você deve evitar testes que se baseiam nos detalhes da implementação, se puder, mas não é tudo ou nada. Às vezes, tudo bem, o pior que acontece é que você altera a implementação e precisa atualizar o teste.

M. Dudley
fonte
2

O objetivo de um teste é restringir as possíveis implementações produtivas. Certifique-se de colocar apenas restrições à implementação realmente necessárias. Normalmente, é isso que seu programa deve fazer, e não como ele faz.

Portanto, se, por exemplo, seu serviço adicionar algo ao repositório, você deve testar se a nova entrada está contida no repositório posteriormente e não se a ação de adição é acionada.

Para que isso funcione, você precisa poder usar a implementação do repositório (testada em outro lugar) no teste do serviço. Descobri que usar a implementação real de um colaborador geralmente é uma boa abordagem - porque é realmente a melhor implementação existente.


"Então, mas e se o uso de implementações reais no teste for caro (por exemplo, porque eles exigem recursos complicados de configurar)? Eu preciso usar zombarias nesse caso, certo?"

Em qualquer caso, você provavelmente desejaria um teste de integração que testa se as implementações reais funcionam juntas. Certifique-se de que este teste de integração seja o necessário para testar seu serviço. Ou, em outras palavras: se um serviço conectar muitos colaboradores (e, portanto, é potencialmente difícil de testar), verifique se ele não contém lógica. Se isso acontecer, e você precisará de vários testes (de integração), precisará alterar a estrutura do seu código, por exemplo, isolando a lógica e, portanto, tornando-a mais testável.

O uso de zombarias nesse caso facilita a tarefa de testar um pedaço de lógica mal isolada e, portanto, oculta um problema arquitetural . Portanto, não use zombarias para testar código mal estruturado, mas corrija a estrutura.

Oberlies
fonte
1
Entendo o que você está dizendo. Este tópico é um pouco confuso quanto a "quanto teste é muito teste", digamos que eu tenho um "serviço agregado" que basicamente é uma fachada e apenas "cola" um monte de outros serviços / repositórios / componentes que tipo de testes você escreve para isso? Tudo o que consigo pensar é na verificação de chamadas. Espero estar fazendo sentido.
Dimitar Dimitrov
2

Meus pensamentos são: 'serviços agregados'.

A verificação de chamadas fará isso, mas não fornecerá muito valor. Você está apenas checando sua fiação.

Existem três maneiras não exclusivas de fazer isso:

  1. Estenda os testes que você tem para cada serviço individual para verificar o comportamento de nível superior. Por exemplo, se você estiver acessando um banco de dados na memória em seus testes de unidade do serviço, suba um nível para testar o serviço em relação a um banco de dados real. A camada de serviço é mais alta na árvore de abstração, e o teste também deve ser feito.

  2. Use a geração de código para criar o serviço diretamente dos serviços agregados.

  3. Use algum tipo de reflexão ou linguagem dinâmica para fazer a mesma coisa. Por exemplo, em Java, pode ser possível usar uma interface groovy, que transmite a chamada diretamente.

Provavelmente, existem outras maneiras de fazer isso, mas apenas verificar a fiação tem um retorno muito baixo e o conectará com essa implementação.

andrew oxenburgh
fonte