Os testes de unidade devem cobrir apenas o software 'funcional'

9

Estamos usando o StructureMap em um novo projeto de desenvolvimento de software. Um dos membros da equipe implementou um teste de unidade que basicamente testa a configuração do contêiner do StructureMap . Faz isso fazendo o seguinte;

  • Conta o número de instâncias de assemblies configurados para classes em nosso espaço para nome do aplicativo.
  • Define as instâncias esperadas no nível da classe
  • Afirma que as instâncias esperadas correspondem ao total de instâncias encontradas.
  • Afirma que as instâncias esperadas correspondem às definidas no teste

Um exemplo disso é;

var repositories = container.GetAllInstances<IEnvironmentRepository>();
Assert.AreEqual(1, repositories .Count());
foundInstances = foundInstances + repositories .Count();

Também temos 'testes de unidade' para a seguinte classe;

public MyClass(IEnvironmentRepository environmentRepository)
        {

        }

Nesses testes, simulamos o IEnvironmentRepository, para não injetá-lo do contêiner, como aconteceria no sistema ativo.

Um colega ignorou o teste de unidade na configuração do mapa de estrutura com um comentário ao longo da linha "Teste de unidade apenas testa sua própria configuração". Obviamente, esse foi o objetivo do teste e, na minha opinião, é perfeitamente válido. Pedi ao cara que ignorou o teste para remover a configuração do mapa de estrutura IEnvironmentRepository(com o teste ainda ignorado) e executar o conjunto de testes de unidade completo, todos eles passaram. Em seguida, executamos o aplicativo e ele caiu porque a configuração do contêiner agora era inválida. Na minha opinião, isso provou o valor do teste, meu colega ainda discordava. Ele simplesmente declarou que não deveríamos testar a configuração, mas considero que isso está dentro da área de um teste de unidade.

Então, várias perguntas;

  • É um teste de unidade válido - Estamos testando a configuração do nosso contêiner, não que o mapa de estrutura funcione (mas posso ver a sobreposição)
  • Caso contrário, como você pode validar a configuração sem testá-la. Como você pode impedir que alguém exclua acidentalmente uma linha de código necessária e faça o check-in?
  • O MyClassteste de unidade deve resolver a instância do IEnvironmentRepositorycontêiner e passar isso?
ChrisBint
fonte
10
9 em 10 discordâncias sobre testes surgem do fato de que as estruturas suportam testes automatizados em todas as suas formas, e as pessoas querem entrar na semântica de saber se um teste automatizado específico é um teste de unidade bom e adequado ou não. O teste que você descreve soa como o tipo de teste não muito unitário que pode muito bem ser útil para automatizar e executar (e executar no check-in) - apenas não o chame de teste unitário. Pergunte se seu colega dormirá melhor à noite se o teste residisse em seu próprio recurso / pasta claramente separado.
Jeroen Mostert
2
Essa também é minha opinião, provavelmente útil, e embora não seja estritamente um teste de unidade, ela agrega valor e isso foi comprovado. Sua resposta foi que os outros testes de unidade teriam percebido isso, mas, na minha opinião, se eles fossem escritos como testes de unidade estritos, você zombaria das dependências e, portanto, nunca saberia se a configuração era válida até que você a usasse.
ChrisBint
4
Seu colega tem um ponto em que ele diz para não testar a configuração, pois a configuração genuína que pode variar de acordo com a implantação não pode / não deve ser testada - quem pode dizer que "vermelho" está errado e "azul" não? O teste seria fortemente acoplado a uma configuração. Mas a configuração vinculada a artefatos de código é uma exceção, porque não varia e há claramente maneiras de cometer erros. Idealmente, você teria essa configuração gerada no momento da construção a partir de metadados DRY, mas onde isso não for possível, um teste como esse agrega valor. Melhor que um erro de implantação evitável.
Jeroen Mostert
2
O que você está descrevendo não testa uma unidade, ele testa a configuração de um software de terceiros. É extraordinariamente útil ter testes que testam essas coisas, mas são testes de integração, não testes de unidade, e a desconexão pode estar na raiz do desacordo.
Phoshi
3
@ChrisBint Goodness gracioso não, eu mesmo escrevi vários testes de contêineres. Eles têm muito valor, simplesmente não são testes de unidade. Tudo bem, os testes de integração são extremamente valiosos para detectar coisas que os testes de unidade não podem .
Phoshi

Respostas:

13

Este é um teste automatizado perfeitamente válido. Eu os chamo de "testes de arquitetura", pois eles verificam a integridade dos componentes esqueléticos da sua base de código.

O contêiner de IoC é capaz de resolver e compor todas as árvores de objetos no aplicativo? O mapeador automático pode mapear entre todos os seus objetos registrados sem falhar? A camada central em uma arquitetura Onion não faz referência a nada externo?

Esses testes podem economizar muito tempo quando um bug de configuração ocorre, apontando o culpado exato. Boas estruturas fornecerão mensagens de erro muito precisas sobre o que está errado e você as receberá assim que executar os testes (idealmente, continuamente) em vez de enterrar no fundo um rastreamento de pilha de tempo de execução, se tiver sorte.

Sejam testes de unidade ... provavelmente não, mas eles ainda operam na memória em sua maior parte e funcionam muito rápido. Então, novamente, eu não sei, não é como se houvesse uma definição universalmente aceita de teste de unidade.

guillaume31
fonte
Ironicamente, foi assim que expliquei ao meu colega e, mesmo com a validação (exclua uma das instâncias do contêiner e execute o aplicativo), ele ainda não estava vendo nenhum valor. Eu entendo que todo mundo tem sua própria opinião e expressei a minha;) Adoro o termo "teste de arquitetura", vou roubar isso!
ChrisBint
6

O problema com um teste como este que testa os aspectos internos do programa, em vez de um requisito dele. É que o teste pode falhar, mesmo que o programa funcione conforme necessário.

No seu caso, sempre que alterar a configuração do contêiner, talvez você tenha uma nova dependência que precisa ser injetada, você deve fazer um teste.

Além disso, se você adicionar o requisito de dependência extra, mas esqueça de adicioná-lo ao contêiner e altere o teste do contêiner. tudo passará, mas seu programa falhará.

Um teste automatizado melhor seria iniciar o programa e verificar se ele falha.

Você deve capturar esses tipos de erro nos testes de integração ou interface do usuário, mesmo se eles passarem pelos testes de unidade.

Dito isto, a crescente complexidade da configuração de contêineres é um pé no saco. Talvez alguns testes "ruins" valham a pena.

Ewan
fonte
1

Código de teste dos testes unitários. Qualquer coisa fora disso é "outro" teste automatizado - chame como quiser. Você parece estar testando a configuração aqui. Se a configuração puder mudar dependendo do ambiente, ela não pertence a um teste de unidade. Considere adicionar um atributo de teste para indicar que o teste é de um tipo diferente dos outros testes.

Robbie Dee
fonte
A configuração é estática, não é orientada pelo ambiente, todas as classes existentes na configuração serão usadas em todos os ambientes da mesma maneira. Sim, o número de instâncias que podem estar na configuração deve corresponder ao número de instâncias na configuração, que faz parte do teste. Como meu exemplo mostrou, a remoção de IEnvironmentRepository permitiu que os outros testes de unidade passassem. O teste de contêiner específico teria falhado em 2 declarações; 1 - O número total de possíveis declarações de instância não correspondeu e 2 - o número específico de instâncias do IEnvironmentRepository não correspondeu.
ChrisBint
11
A correção do contêiner é definida pelo codificador. O fato de que tanto o código sob teste quanto o próprio teste precisam ser alterados para cada modificação imediatamente acionam os alarmes. O DI é um meio para um fim e não o fim em si mesmo. É perfeitamente possível escrever código em um estilo DI sem um mapa de estrutura, portanto, na minha opinião, não é um teste de unidade de boa-fé. É claro que o contêiner precisa ser comprovado, mas a eficácia de fazê-lo com testes automatizados parece um pouco controversa com as informações limitadas fornecidas aqui.
Robbie Dee
2
Os testes de unidade levaram 10 minutos para serem concluídos. A implantação pode levar mais de uma hora.
ChrisBint
11
Dado que parte do teste de unidade valida especificamente a existência de uma única linha na configuração, não sei como isso não poderia ter sido mais isolado. A contagem geral com a qual concordo.
ChrisBint
11
Poderia haver alguma milhagem neles então - um julgamento para você realmente. Mas eles devem ser separados fisicamente ou através de algum atributo.
Robbie Dee
0

A responsabilidade do contêiner de injeção de dependência é colar diferentes módulos em um aplicativo em funcionamento .

Se você escrever testes automatizados para o seu aplicativo - deverá ter poucos testes de "integração (ou aceitação) que executem testes" de ponta a ponta ", que testarão todo o pipeline do seu aplicativo, para que todos os módulos envolvidos em um caso de teste específico sejam colados juntos corretamente .

Portanto, esses testes de integração falharão se o contêiner de injeção de dependência não tiver sido configurado corretamente. O que torna inúteis os testes de unidade do contêiner, porque o teste de integração deve mostrar possíveis erros na configuração do contêiner.

Você não precisa cobrir todos os casos de teste possíveis nos testes de integração, apenas um caso de teste por recurso, que abrange todo o caminho da interface do usuário ao banco de dados.

Se os casos de teste de integração não cobrirem a instanciação de alguma dependência específica - você simplesmente adiciona essa.

Com os testes de integração, você pode alterar livremente os contêineres sem reescrever os testes de unidade para sua configuração.

Fabio
fonte
0

IMO, as respostas são:

  1. É um teste de unidade válido - Estamos testando a configuração do nosso contêiner, não que o mapa de estrutura funcione (mas posso ver a sobreposição)

    • É um teste de unidade válido para o mapa de estrutura , não para o seu projeto, porque um teste unitário testa algum código específico, zombando de todas as dependências, se necessário, para testar a lógica implementada. A lógica de configuração é implementada dentro do structuremap, portanto, esta biblioteca deve ser bem testada e deve conter testes de unidade como este que você mencionou e muito mais: deve conter centenas de testes como esse, zombando dinamicamente de várias configurações em tempo de execução e testando para verificar se o recipiente se comporta como deveria.
  2. Caso contrário, como você pode validar a configuração sem testá-la. Como você pode impedir que alguém exclua acidentalmente uma linha de código necessária e faça o check-in?

    • Você pode testar a configuração manualmente no ambiente necessário e também pode criar uma automação para este (teste automatizado), que testa a configuração específica que você precisa (sem necessidade de zombar de coisas em tempo de execução).
  3. O teste de unidade MyClass deve resolver a instância de IEnvironmentRepository do contêiner e passar isso?

    • Não, este é um teste de unidade perfeito, porque você zomba da dependência e testa a lógica do MyClass de maneira isolada.
Emerson Cardoso
fonte
-1

O UnitTest verifica o comportamento desejado de uma unidade em separação .

Isso significa que qualquer tipo de configuração não está no escopo de UnitTests .

No entanto, você deve ter testes automatizados para suas configurações, mas estes não são testes de unidade ...

Timothy Truckle
fonte
Onde você está obtendo a definição de Units?
ChrisBint
Gosto do de Roy Osherove em The Art Of Unittesting : A Unit é qualquer pedaço de código (de produção) que tem o mesmo motivo para mudar. I meu mundo isso geralmente varia de uma única classe até três ou cinco ...
Timothy Truckle
Este é o código de produção que está sendo testado.
ChrisBint
Só queria distrair os nitpickers , não esperando que funciona no sentido inverso também ...; o)
Timothy Truckle