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 umvoid
Por 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.
fonte
Respostas:
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.
fonte
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.
fonte
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:
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.
Use a geração de código para criar o serviço diretamente dos serviços agregados.
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.
fonte