Como evito que meus testes de unidade exigirem conhecimento sobre a implementação internos ao usar objetos simulados?

StackOverflow https://stackoverflow.com/questions/3448121

Pergunta

Ainda estou nos estágios de aprendizado sobre o teste de unidade e, em particular, em relação a zombarias (estou usando o Pascalmock e Dunit estruturas). Uma coisa que agora tropecei foi que não consegui encontrar uma maneira de contornar os detalhes da implementação de codificação da interface/interface testada no meu teste de unidade e isso parece errado ...

Por exemplo: quero testar uma classe que implementa uma interface muito simples para ler e escrever configurações de aplicativos (basicamente pares de nome/valor). A interface apresentada ao consumidor é completamente agnóstica a onde e como os valores são realmente armazenados (por exemplo, registro, Ini-File, XML, banco de dados, etc.). Naturalmente, a camada de acesso é implementada por uma classe diferente que é injetada na classe testada na construção. Criei um objeto simulado para essa camada de acesso e agora sou capaz de testar completamente a classe de implementação de interface sem realmente ler ou escrever nada para nenhum registro/arquivo ini/o que for.

No entanto, para garantir que a simulação se comporte exatamente como a coisa real quando acessada pela classe testada, meus testes de unidade precisam configurar o objeto simulado, definindo muito explicitamente as chamadas de método esperadas e os valores de retorno esperados pela classe testada. Isso significa que, se eu precisar fazer alterações na interface da camada de acesso ou à maneira como a classe testada usa essa camada, também terei que alterar os testes de unidade para a classe que usa internamente essa interface, mesmo que o interface Da aula que estou realmente testando não mudou. Isso é algo com o qual terei que conviver ao usar zombarias ou existe uma maneira melhor de projetar as dependências de classe que evitariam isso?

Foi útil?

Solução

Isso é algo com o qual terei que conviver ao usar zombarias ou existe uma maneira melhor de projetar as dependências de classe que evitariam isso?

Muitas vezes zombam (principalmente estruturas sensíveis como o JMOCK) o forçam a explicar detalhes que não se relacionam diretamente com o comportamento que você está tentando testar, e às vezes isso pode até ser útil ao expor o código suspeito que está fazendo muito e tem muitas chamadas/dependências.

No entanto, no seu caso, se eu ler sua descrição corretamente, parece que você realmente não tem um problema. Se você projetar a camada de leitura/gravação corretamente e com um nível apropriado de abstração, não precisará alterá -la.

Isso significa que, se eu precisar fazer alterações na interface da camada de acesso ou à maneira como a classe testada usa essa camada, também terei que alterar os testes de unidade para a classe que usa internamente essa interface, mesmo que a interface Da aula que estou realmente testando não mudou.

Não é o sentido de escrever a camada de acesso abstrata para evitar isso? Em geral, seguindo o Princípio aberto/fechado, uma interface desse tipo não deveria Mudar e não deve quebrar o contrato com a classe que o consome e, por extensão, ele também não interrompe seus testes de unidade. Agora, se você alterar a ordem do método chama ou precisar fazer novas chamadas para a camada abstrata, então, sim, particularmente com algumas estruturas, suas expectativas simuladas quebrarão. Isso é apenas parte do custo do uso de zombarias e é perfeitamente aceitável. Mas a própria interface deve, em geral, permanecer estável.

Outras dicas

Para garantir que a simulação se comporte exatamente como a coisa real quando acessada pela classe testada, meus testes de unidade precisam configurar o objeto simulado, definindo explicitamente as chamadas de método esperadas e os valores de retorno esperados pela classe testada.

Correto.

Alterações na interface da camada de acesso ou à maneira como a classe testada usa essa camada, também terei que alterar os testes de unidade

Correto.

Mesmo que a interface da aula que estou testando não tenha mudado.

"Na verdade, testando"? Você quer dizer a classe de interface exposta? Isso é bom.

A maneira como a classe "testada" (interface) usa a camada de acesso significa que você alterou a interface interna para a camada de acesso. As alterações da interface (mesmo as internas) requerem alterações no teste e podem levar à quebra se você fez algo errado.

Nada de errado com isso. De fato, o ponto principal é que qualquer alteração na camada de acesso devo exigem alterações nas zombarias para garantir que a mudança "funciona".

Os testes não devem ser "robustos". Deveria ser quebradiço. Se você fizer uma mudança que altera o comportamento interno, então as coisas posso parar. Se seus testes fossem muito robustos, eles não testariam nada - eles apenas funcionariam. E isso está errado.

Os testes devem funcionar apenas pelo motivo exato certo.

Apenas para colocar alguns nomes no seu exemplo,

  • RegistryBasedDictionary implementa o dicionário de função (interface).
  • O RegistryBasedDictionary tem uma dependência do papel RegistryAccessor, implementado pelo RegistryWinapiwrapper.

Atualmente, você está interessado em testar o RegistryBasedDictionary. Os testes de unidade injetariam uma dependência simulada para a função do RegistryAccessor e testaria a interação esperada com as dependências.

  • O truque aqui para evitar a manutenção desnecessária é "Especifique com precisão o que deve acontecer .. e não mais." (A partir de o livro de gansas (Leia obrigatória para TDD com sabor simulado); portanto, se o método da ordem de dependência Chamadas não importa, não o especifique no teste. Isso deixa você livre para alterar a ordem das chamadas na implementação.)
  • Projete as funções de modo que eles não contêm vazamentos das implementações reais - Mantenha as funções implementação-agnóstica.

A única razão para alterar os testes do registro baseado no registro, seria uma mudança no comportamento do registro de registro e não em nenhuma de suas dependências. Então, se for Interação com suas dependências ou funções/contratos mudam, os testes precisariam ser atualizados. Esse é o preço dos testes baseados em interação que você precisa pagar, pela flexibilidade de testar isoladamente. No entanto, na prática, isso não acontece com tanta frequência.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top