Como devo testar meu código de teste?

22

Uma das poucas coisas que a maioria dos desenvolvedores de software concorda é que você não deve confiar no código para funcionar corretamente, a menos que você o teste. Se você não testá-lo, pode haver erros ocultos que só irão causar mais trabalho no caminho.

Entendo como testar meu código normal, mas como devo testá-lo para garantir que ele encontre e relate erros de maneira eficaz quando presentes? Pessoalmente, fui estúpido o suficiente para escrever casos de teste errados que passariam quando não deveriam, derrotando, assim, o propósito dos meus testes de escrita. Felizmente, encontrei e corrigi os erros com o tempo, mas, de acordo com o mantra de teste, parece que nenhum conjunto de testes estaria completo sem ter seu próprio conjunto de testes para garantir que funcionasse.

Parece-me que a melhor maneira de fazer isso seria garantir que o teste falhe para o código de buggy. * Se eu passar 2 minutos alternadamente adicionando bugs ao código e me certificando de que ele falhar, eu deveria ter um grau aceitável de confiança de que os testes 'funcionam'. Isso me leva à minha segunda pergunta: Quais são as boas maneiras de introduzir bugs para garantir que eles sejam capturados pelos casos de teste? Devo apenas comentar aleatoriamente declarações, certifique-se o ramo errado de um if-elseé executado negando sua condição e alterar a ordem de execução de código com efeitos colaterais, etc., até que eu estou satisfeito meus testes vai pegar maiserros comuns? Como os desenvolvedores profissionais validam que seus testes realmente fazem o que deveriam fazer? Eles apenas assumem que os testes funcionam, ou eles tomam tempo para testá-los também? Se sim, como eles testam os testes?

Não estou sugerindo que as pessoas devam gastar tanto tempo testando seus testes e testando-os para que nunca escrevam o código real, mas fiz coisas estúpidas o suficiente para me beneficiar um pouco. de 'meta-teste' e estava curioso sobre a melhor maneira de fazer isso. : D

* Eu poderia verificar se o teste é aprovado ao testar o código 'sem erros', mas usar o código como uma especificação para o teste parece um tanto atrasado ...

Gordon Gustafson
fonte
Parece que você não confia nos seus testes de unidade - provavelmente porque lhe falta muita experiência em escrever testes? Nesse caso, não seria razoável escrever mais testes e esperar um resultado diferente. Continue fazendo o que está fazendo, seja o mais completo possível (teste de falhas e também de sucesso) e logo seus testes de unidade começarão a pagar por si mesmos - e sua confiança neles aumentará.
MattDavey
Possível duplicata de Como testar os testes?
gnat
Antes de usar mais ferramentas, use suas ferramentas reais melhor . Escreva menos testes, mas testes mais eficientes e melhores. Você não pode confiar em algo que não entende.
Steve Chamaillard 19/01

Respostas:

16

O fluxo padrão para TDD é:

  1. Escreva um teste com falha. (Vermelho)
  2. Faça a menor alteração de código que a faça passar (Verde)
  3. Refatorar (mantendo-o verde)

O teste para seus testes neste caso é a etapa 1 - verifique se o teste falha antes de fazer alterações no código.

Outro teste de que gosto é se você pode excluir algum código e reimplementá-lo de uma maneira diferente, e seus testes falham após a exclusão, mas funcionam com um algoritmo diferente.

Como em todas as coisas, não há bala mágica. Esquecer-se de escrever um teste obrigatório é tão fácil para um desenvolvedor quanto esquecer de escrever o código. Pelo menos se você estiver fazendo as duas coisas, terá duas vezes mais oportunidades para descobrir sua omissão.

Bringer128
fonte
4
Contabilidade dupla: os testes de unidade testam o código de produção e vice-versa. São duas maneiras diferentes de indicar o mesmo problema. Como na contabilidade dupla, onde você registra suas transações de duas maneiras diferentes e ambas devem obter os mesmos totais.
precisa saber é o seguinte
A pergunta é sobre o problema quando a etapa 2 torna o teste verde, mesmo que o código ainda esteja com erros. Exemplo simples: você tem uma função que deve retornar um ponteiro para um objeto de lista não vazio. Seu teste testa se o ponteiro está nullou não na etapa 1. Você faz a menor alteração de código que o faz passar retornando uma lista vazia. O teste agora é "verde" porque você tem dois erros.
Christian Hackl em
@ChristianHackl nessa fase de desenvolvimento, é uma implementação perfeita! Você precisa adicionar um (ou mais) testes que falham no início para especificar melhor o comportamento esperado. Posteriormente, você o implementa, deixando esses testes verdes.
Andy
@ Andy: Importa-se de elaborar como essa é uma implementação perfeita quando eu tenho um bug no código e no teste, e um impede que eu observe o outro? (O erro no código é que uma lista vazia é retornada, e o erro no teste é que eu procuro por nulle não por esvaziar.)
Christian Hackl
@ChristianHackl você está certo de acordo com o cheque vazio. Isso também deve ser feito em um teste. Quando você traduz seus requisitos para testes, passo a passo, há pouco espaço para erros. Exceto aqueles em que você não se atém às especificações (como ignorar uma verificação não vazia).
Andy
9

Uma abordagem é o Teste de mutação , usando uma ferramenta como o Jester :

O Jester faz alguma alteração no seu código, executa seus testes e, se os testes forem aprovados, o Jester exibirá uma mensagem dizendo o que mudou

parsifal
fonte
4

Testes para testes? Não siga por esse caminho. Então você provavelmente precisará de testes para testes para testes e, em seguida, testes para testes para testes para testes ... onde você para?

O fluxo de teste usual é assim e, como desenvolvedor, você passará a maior parte do tempo nos pontos 1 a 3:

  1. Código
  2. Testes unitários
  3. Testes de integração
  4. Sistema / outro automatizado
  5. QA / testadores humanos

Se eu passar 2 minutos adicionando bugs alternadamente ao código (...)

Seu código acabará "aumentando" seus próprios bugs, não perca tempo introduzindo-os manualmente. Sem mencionar, uma coisa que você sabia sobre o início é realmente um bug? Erros virão, eu não me preocuparia com isso.

Devo apenas comentar aleatoriamente as instruções, verifique se o ramo errado de um if-else é executado negando sua condição (...)

Essa é realmente uma abordagem viável para verificar se você realmente testa o que pensa fazer. Eu não acho que é sempre tão bom , pois sofre do mesmo problema que a coisa "teste para teste para teste ...": quando você para de alterar o código sabendo que está testando 100% funciona?

Também é bom lembrar sobre todos os conselhos pragmáticos clássicos de todos os tempos - você não precisará disso . Seja ágil, escreva testes e codifique erros reais, em vez daqueles hipotéticos que podem ou não aparecer.

km
fonte
3
Não estou preocupado com meu código aumentando seus próprios bugs, estou preocupado com meus testes pegando-os quando eles acontecem. Se meus testes estiverem com defeito, eles não farão o trabalho deles e eu pensarei que me livrei de uma certa classe de bug quando eles ainda existem, apenas dificultando meu trabalho porque estou vendo resultados imprecisos (passe quando eles devem falhar).
Gordon Gustafson
@CrazyJugglerDrummer: seus testes não capturam todos os bugs, com certeza. Eles não servem a esse propósito - é aqui que entra o controle de qualidade. Se o fizessem, isso significaria que o software está livre de erros, a menos que o código-fonte seja alterado, o que eu nunca vi.
km
3

Por construção, o código funcional e o código de teste são testados um contra o outro. Um problema permanece: o caso de erros no modo comum, quando um erro no código funcional é oculto por um erro no código de teste. TDD não é imune a esse efeito. É por isso que o teste geralmente é realizado em vários níveis por pessoas diferentes, a fim de diminuir essa probabilidade.

mouviciel
fonte
0

Você testa seu teste de unidade uma vez ao escrevê-lo, no depurador. Então você deixa em paz e esquece. Não há problema aqui.

Considere isto. Qual é o objetivo de um teste de unidade? Ele o notifica quando qualquer uma das inúmeras alterações que você fizer no seu programa principal acidentalmente altera a lógica desse programa. Você quer ter isso porque sabe que qualquer alteração potencialmente quebra alguma coisa. É exatamente por isso que não há problema se você não testar seu teste: você não mexe com o teste até alterar propositadamente a lógica do seu programa (o que exigiria que você revisitasse o teste e testasse mais uma vez); Provavelmente, o teste não será interrompido acidentalmente.

Martin Maat
fonte
-2

um teste de mutação que avalia e mede a adequação e a qualidade do teste.

Podemos usar isso para avaliar "o teste" em si.

Em resumo, podemos avaliar nosso teste (por exemplo, TestA) testando TestA pode encontrar a diferença entre o código e seus códigos de mutação (código muito semelhante, mas um pouco diferente do código original).

Se o TestA não conseguir encontrar a diferença entre o código e seus códigos de mutação, significa que o TestA possui regulamentos muito rígidos para testar o código original.

Caçador de frango
fonte