Quanta zombaria é "certa"?

10

Eu intitulei a pergunta de brincadeira, porque tenho certeza de que "depende", mas tenho algumas perguntas específicas.

Trabalhando em software que possui muitas camadas profundas de dependência, minha equipe se acostumou a usar a simulação bastante extensivamente para separar cada módulo de código das dependências abaixo dele.

Portanto, fiquei surpreso que Roy Osherove tenha sugerido neste vídeo que você deveria usar zombaria apenas em 5% das vezes. Eu acho que estamos sentados em algum lugar entre 70-90%. Vi outras orientações semelhantes de tempos em tempos também.

Devo definir o que considero duas categorias de "testes de integração" que são tão distintos que realmente devem receber nomes diferentes: 1) Testes em processo que integram vários módulos de código e 2) Testes fora de processo que falam para bancos de dados, sistemas de arquivos, serviços web, etc. É do tipo # 1 que me preocupo, testes que integram vários módulos de código em processo.

Muitas das orientações da comunidade que li sugerem que você deve preferir um grande número de testes de unidade isolados e refinados e um pequeno número de testes de integração de ponta a ponta de granulação grossa, porque os testes de unidade fornecem um feedback preciso sobre exatamente onde regressões podem ter sido criadas, mas os testes grosseiros, difíceis de configurar, na verdade verificam mais funcionalidades de ponta a ponta do sistema.

Diante disso, parece necessário fazer uso bastante frequente de zombaria para isolar essas unidades de código separadas.

Dado um modelo de objeto da seguinte maneira:

insira a descrição da imagem aqui

... Considere também que a profundidade de dependência do aplicativo é muito mais profunda do que eu poderia caber nesta imagem, para que haja várias camadas N entre a camada 2-4 e a camada 5-13.

Se eu quiser testar alguma decisão lógica simples que está sendo tomada na unidade nº 1, e se toda dependência for injetada por construtor no módulo de código que depende dele, de modo que, digamos, 2, 3 e 4 sejam injetados em construtor no módulo 1 em Na imagem, prefiro injetar simulações de 2, 3 e 4 em 1.

Caso contrário, eu precisaria construir instâncias concretas de 2, 3 e 4. Isso pode ser mais difícil do que apenas uma digitação extra. Frequentemente 2, 3 e 4 terão requisitos de construtor que podem ser difíceis de satisfazer e de acordo com o gráfico (e de acordo com a realidade do nosso projeto), precisarei construir instâncias concretas de N a 13 para satisfazer os construtores de 2, 3 e 4.

Essa situação se torna mais desafiadora quando preciso que 2, 3 ou 4 se comportem de uma certa maneira, para que eu possa testar a simples decisão lógica no # 1. Talvez eu precise entender e "raciocinar mentalmente" todo o gráfico / árvore de objetos de uma só vez, para que 2, 3 ou 4 se comportem da maneira necessária. Muitas vezes parece muito mais fácil executar myMockOfModule2.Setup (x => x.GoLeftOrRight ()). Returns (new Right ()); para testar se o módulo 1 responde conforme o esperado quando o módulo 2 diz para ele dar certo.

Se eu testasse instâncias concretas de 2 ... N ... 13 juntas, as configurações de teste seriam muito grandes e quase sempre duplicadas. As falhas no teste podem não fazer um bom trabalho ao identificar os locais das falhas nas regressões. Os testes não seriam independentes ( outro link de suporte ).

Concedido, geralmente é razoável fazer testes da camada inferior com base no estado, e não na interação, pois esses módulos raramente têm outra dependência. Mas parece que a zombaria é quase necessária por definição para isolar quaisquer módulos acima do nível mais baixo.

Dado tudo isso, alguém pode me dizer o que posso estar perdendo? Nossa equipe está abusando da zombaria? Ou talvez haja alguma suposição nas orientações típicas de teste de unidade de que as camadas de dependência na maioria dos aplicativos serão superficiais o suficiente para que seja realmente razoável testar todos os módulos de código integrados juntos (tornando nosso caso "especial")? Ou talvez de outra maneira, nossa equipe não está limitando adequadamente nossos contextos limitados?

ardave
fonte
Parece-me que seu aplicativo pode se beneficiar de um acoplamento mais flexível. en.wikipedia.org/wiki/Loose_coupling
Robert Harvey
1
Or is there perhaps some assumption in typical unit testing guidance that the layers of dependency in most applications will be shallow enough that it is indeed reasonable to test all of the code modules integrated together (making our case "special")? <- Isso.
Robert Harvey
Também digno de nota: O objetivo dos testes de regressão (especialmente os testes de integração) é provar que seu software ainda funciona, não necessariamente para identificar onde ele é interrompido. Você pode fazer isso com a solução de problemas, corrigir o problema e, em seguida, cobrir a quebra específica com testes de unidade adicionais.
Robert Harvey
Eu deveria ter sido mais claro no post original, para dizer que o módulo 1 só conhece I2, I3 e I4. O módulo 2 conhece apenas I5, I6 e I7. É apenas o objetivo questionável de testar sem o uso de simulações que eu forneceria um concreto 2, 3 e 4 a 1, levando aos desafios que descrevi. Caso contrário, acabamos usando zombarias em mais de 5% do tempo.
Ardave # 15/13
Eu meio que brinquei com o fato de o nosso caso ser "especial" depois de ler um post no blog sobre muitas equipes desafiando convenções valiosas porque, incorretamente, achavam que sua situação era "especial". Mas se esse for realmente o nosso caso, isso explicaria a disparidade entre algumas das orientações da comunidade que eu li e algumas das experiências reais da minha equipe. (the 5% vs 70-90%)
ardave

Respostas:

4

Nossa equipe está abusando da zombaria?

Não à primeira vista.

Se você tiver 1..13 módulos, cada um deverá ter seus próprios testes de unidade e todas as dependências (não triviais, não confiáveis) devem ser substituídas pelas versões de teste. Isso pode significar zombarias, mas algumas pessoas são pedantes com nomes, falsificações, calços, objetos nulos ... algumas pessoas se referem a todas as implementações de teste como "zombarias". Essa pode ser a fonte da confusão sobre o quanto é "certo".

Pessoalmente, eu chamo todos os objetos de teste de "zombaria" porque a distinção entre a variedade deles nem sempre é útil. Contanto que eles mantenham meus testes de unidade rápidos, isolados e resistentes ... Eu não me importo com o nome deles.

Telastyn
fonte
Gostaria de saber então se existe alguma orientação geral para quando é melhor testar os módulos de código isoladamente versus testar mais de um módulo de código, integrado em conjunto. Parece que assim que integro dois módulos que eu poderia ter isolado, eu me abro para uma série de problemas indesejáveis: falta de identificação de causas de regressão / vários testes falhando em uma única regressão, configurações de teste excessivas etc. Eu tenho meu próprio senso intuitivo ("ouça os testes"), mas isso me deixou no nível de simulação de 70 a 90%.
ardave
1
@nono - Na minha experiência, você deve testar tudo isoladamente, pelos motivos mencionados. As únicas coisas que você não realiza o teste de unidade isoladamente são coisas que não pode, porque elas vão contra algum sistema de arquivos ou outro recurso externo diretamente ( algo precisa fazer isso, afinal).
Telastyn #
Depois de analisar isso por alguns dias, a sua parece ser a melhor explicação possível: se alguém usasse a definição estrita de "simulação" como um tipo de teste duplo usado para verificação retrospectiva de interação / comportamento, em oposição a um teste simulado duplo ou um teste duplo que é configurado antecipadamente para simular um certo comportamento; então, sim, eu pude ver terminando no nível de 5%.
Ardave 18/10/2013