Acabei de terminar a faculdade e estou começando a universidade em algum lugar na próxima semana. Vimos testes de unidade, mas meio que não os usamos muito; e todo mundo fala sobre eles, então pensei que talvez devesse fazer um pouco.
O problema é que não sei o que testar. Devo testar o caso comum? O caso de ponta? Como sei que uma função está adequadamente coberta?
Eu sempre tenho a terrível sensação de que, embora um teste prove que uma função funciona para um determinado caso, é totalmente inútil provar que a função funciona, ponto final.
Respostas:
Minha filosofia pessoal foi assim:
fonte
Entre a infinidade de respostas até agora, ninguém abordou o particionamento de equivalência e a análise de valor-limite , considerações vitais na resposta à pergunta em questão. Todas as outras respostas, embora úteis, são qualitativas, mas é possível - e preferível - ser quantitativa aqui. O @fishtoaster fornece algumas diretrizes concretas, apenas espiando sob a cobertura da quantificação de testes, mas o particionamento de equivalência e a análise de valor de limite nos permitem fazer melhor.
No particionamento de equivalência , você divide o conjunto de todas as entradas possíveis em grupos com base nos resultados esperados. Qualquer entrada de um grupo produzirá resultados equivalentes, portanto, esses grupos são chamados de classes de equivalência . (Observe que resultados equivalentes não significam resultados idênticos.)
Como um exemplo simples, considere um programa que deve transformar caracteres ASCII minúsculos em caracteres maiúsculos. Outros caracteres devem passar por uma transformação de identidade, ou seja, permanecer inalterados. Aqui está uma possível divisão em classes de equivalência:
A última coluna relata o número de casos de teste, se você enumerar todos eles. Tecnicamente, pela regra 1 do @ fishtoaster, você incluiria 52 casos de teste - todos os das duas primeiras linhas dadas acima se enquadram no "caso comum". A regra 2 da @ fishtoaster adicionaria algumas ou todas as linhas 3 e 4 acima também. Mas, com equivalência de particionamento testar qualquer um caso de teste em cada classe de equivalência é suficiente. Se você escolher "a" ou "g" ou "w", estará testando o mesmo caminho de código. Assim, você tem um total de 4 casos de teste em vez de 52 ou mais.
A análise do valor limite recomenda um ligeiro refinamento: essencialmente, sugere que nem todo membro de uma classe de equivalência é, bem, equivalente. Ou seja, os valores nas fronteiras também devem ser considerados dignos de um caso de teste por si mesmos. (Uma justificativa fácil para isso é o infame erro de um por um !) Portanto, para cada classe de equivalência, você pode ter 3 entradas de teste. Olhando para o domínio de entrada acima - e com algum conhecimento dos valores ASCII -, posso apresentar estas entradas de caso de teste:
(Assim que você obtiver mais de três valores de limite, o que sugere que você pode querer repensar suas delineações de classe de equivalência originais, mas isso foi simples o suficiente para que eu não voltasse a revisá-las.) Assim, a análise de valor de limite nos leva a apenas 17 casos de teste - com uma alta confiança de cobertura completa - em comparação com 128 casos de teste para realizar testes exaustivos. (Sem mencionar que a combinatória determina que testes exaustivos são simplesmente inviáveis para qualquer aplicação do mundo real!)
fonte
Provavelmente minha opinião não é muito popular. Mas sugiro que você seja econômico com testes de unidade. Se você tiver muitos testes de unidade, poderá acabar gastando metade do seu tempo ou mais com a manutenção de testes, em vez da codificação real.
Eu sugiro que você escreva testes para coisas que você tem um mau pressentimento ou coisas muito cruciais e / ou elementares. Os testes de unidade IMHO não substituem uma boa engenharia e codificação defensiva. Atualmente, trabalho em um projeto que é mais ou menos inutilizável. É realmente estável, mas é difícil refatorar. De fato, ninguém tocou esse código em um ano e a pilha de software em que ele se baseia tem 4 anos. Por quê? Porque está cheio de testes de unidade, para ser mais preciso: testes de unidade e testes de integração automatizados. (Já ouviu falar de pepino e coisas do tipo?) E aqui está a melhor parte: Este (ainda) software inutilizável foi desenvolvido por uma empresa cujos funcionários são pioneiros no cenário de desenvolvimento orientado a testes. : D
Então, minha sugestão é:
Comece a escrever testes depois de desenvolver o esqueleto básico; caso contrário, a refatoração poderá ser dolorosa. Como desenvolvedor que desenvolve para outras pessoas, você nunca obtém os requisitos corretamente desde o início.
Verifique se seus testes de unidade podem ser realizados rapidamente. Se você tiver testes de integração (como pepino), tudo bem se eles demorarem um pouco mais. Mas testes de longa duração não são divertidos, acredite. (As pessoas esquecem todos os motivos pelos quais o C ++ se tornou menos popular ...)
Deixe esse material de TDD para os especialistas em TDD.
E sim, às vezes você se concentra nos casos extremos, às vezes nos casos comuns, dependendo de onde espera o inesperado. Embora se você sempre espera o inesperado, deve realmente repensar o fluxo de trabalho e a disciplina. ;-)
fonte
Leave this TDD stuff to the TDD-experts
.Se você estiver testando primeiro com o Test Driven Development, sua cobertura aumentará em 90% ou mais, porque você não adicionará funcionalidade sem primeiro escrever um teste de unidade com falha.
Se você estiver adicionando testes após o fato, não posso recomendar o suficiente para que você obtenha uma cópia do Working Effective With Legacy Code de Michael Feathers e dê uma olhada em algumas das técnicas para adicionar testes ao seu código e maneiras de refatorar seu código para torná-lo mais testável.
fonte
The problem is, I don't know _what_ to test
Se você começar a seguir test driven development práticas, eles tipo irá guiá- lo através do processo e saber o que testar virá naturalmente. Alguns lugares para começar:
Os testes vêm primeiro
Nunca, nunca escreva código antes de escrever os testes. Consulte Vermelho-verde-refator-repetição para obter uma explicação.
Escrever testes de regressão
Sempre que encontrar um bug, escreva um testcase e verifique se ele falha . A menos que você possa reproduzir um bug através de uma caixa de teste com falha, você realmente não o encontrou.
Repetição de vermelho-verde-refator
Vermelho : comece escrevendo um teste mais básico para o comportamento que você está tentando implementar. Pense nesta etapa como escrevendo algum código de exemplo que usa a classe ou função em que você está trabalhando. Verifique se ele compila / não possui erros de sintaxe e se falha . Isso deve ser óbvio: você não escreveu nenhum código, portanto deve falhar, certo? O importante a aprender aqui é que, a menos que você veja o teste falhar pelo menos uma vez, nunca poderá ter certeza de que, se for aprovado, o fará por causa de algo que você fez por algum motivo falso.
Verde : escreva o código mais simples e estúpido que realmente faz o teste passar. Não tente ser esperto. Mesmo que você veja que há um caso de borda óbvio, mas o teste leva em consideração, não escreva código para lidar com isso (mas não se esqueça do caso de borda: você precisará dele mais tarde). A idéia é que todo código que você escreve, todo
if
, todotry: ... except: ...
seja justificado por um caso de teste. O código não precisa ser elegante, rápido ou otimizado. Você só quer que o teste seja aprovado.Refatorador : limpe seu código, acerte os nomes dos métodos. Veja se o teste ainda está passando. Otimizar. Execute o teste novamente.
Repita : você se lembra do caso extremo que o teste não cobriu, certo? Então, agora é o seu grande momento. Escreva uma caixa de teste que cubra essa situação, observe-a falhar, escreva algum código, veja-o passar, refatorar.
Teste seu código
Você está trabalhando em algum trecho de código específico, e é exatamente isso que deseja testar. Isso significa que você não deve testar as funções da biblioteca, a biblioteca padrão ou o seu compilador. Além disso, tente evitar testar o "mundo". Isso inclui: chamar APIs da Web externas, algumas coisas intensivas em bancos de dados, etc. Sempre que você tentar zombar (crie um objeto que siga a mesma interface, mas retorne dados estáticos e predefinidos).
fonte
Para testes de unidade, comece com o teste de que ele faz o que foi projetado para fazer. Esse deve ser o primeiro caso que você escreve. Se parte do design é "ele deve gerar uma exceção se você passar para o lixo", teste-o também, pois isso faz parte do design.
Comece com isso. À medida que você obtém experiência na execução dos testes mais básicos, você começa a aprender se isso é suficiente ou não e começa a ver outros aspectos do seu código que precisam de testes.
fonte
A resposta das ações é "testar tudo o que poderia quebrar" .
O que é simples demais para quebrar? Campos de dados, acessadores de propriedades com morte encefálica e despesas gerais semelhantes. Qualquer outra coisa provavelmente implementa alguma parte identificável de um requisito e pode se beneficiar de ser testado.
Obviamente, sua milhagem - e as práticas do seu ambiente de trabalho - podem variar.
fonte