Como testar os testes?

53

Testamos nosso código para torná-lo mais correto (na verdade, menos probabilidade de estar incorreto ). No entanto, os testes também são códigos - eles também podem conter erros. E se os seus testes tiverem erros, dificilmente farão o seu código melhor.

Posso pensar em três possíveis tipos de erros nos testes:

  1. Erros lógicos, quando o programador não entendeu a tarefa em questão, e os testes fazem o que ele acha que devem fazer, o que está errado;

  2. Erros na estrutura de teste subjacente (por exemplo, uma abstração falsa e de fuga);

  3. Erros nos testes: o teste está sendo um pouco diferente do que o programador acha que é.

Os erros do tipo (1) parecem ser impossíveis de evitar (a menos que o programador apenas ... fique mais esperto). No entanto, (2) e (3) podem ser tratáveis. Como você lida com esses tipos de erros? Você tem alguma estratégia especial para evitá-los? Por exemplo, você escreve alguns testes "vazios" especiais, que apenas verificam os pressupostos do autor do teste? Além disso, como você aborda a depuração de um caso de teste quebrado?

    
por Ryszard Szopa 13.10.2010 / 01:04
fonte

10 respostas

17

Os testes já foram testados. Os testes são, por design, protegidos contra os bugs, porque o teste detecta apenas as diferenças entre o código e as nossas expectativas. Se houver problemas, temos um erro. O erro pode estar no código ou com a mesma probabilidade nos testes.

  1. Existem algumas técnicas que o impedem de adicionar o mesmo erro no código e nos testes:

    1. O cliente deve ser uma pessoa diferente do implementador.
    2. Primeiro, escreva os testes e, em seguida, o código (como no Desenvolvimento Orientado a Testes).
  2. Você não precisa testar a plataforma subjacente. Os testes não apenas exercitam o código escrito por você, mas também executam o código da plataforma. Enquanto você não precisa pegar bugs na plataforma de testes, é muito difícil escrever código e testes que sempre escondem um bug na plataforma, ou seja, é muito difícil ter um bug sistemático tanto no seu teste / código quanto na plataforma, e a probabilidade é reduzida com cada teste que você cria. Mesmo se você tentasse fazer isso, teria uma tarefa muito difícil.

  3. Você pode ter erros nos testes, mas geralmente eles são capturados facilmente porque os testes são testados pelo código desenvolvido. Entre o código e os testes, você tem um feedback de auto-imposição. Ambos fazem previsões sobre como uma chamada específica de uma interface deve se comportar. Se a resposta for diferente, você não precisa ter um bug no código. Você pode ter um bug no teste também.

por 13.10.2010 / 02:06
fonte
24

Tente fazer com que os testes individuais sejam pequenos (curtos) possíveis.

Isso deve reduzir as chances de criar um bug em primeiro lugar. Mesmo se você conseguir criar um, é mais fácil encontrá-lo. Os testes unitários devem ser pequenos e específicos, com baixa tolerância a falhas e desvios.

No final, é provavelmente apenas uma questão de experiência. Quanto mais testes você escrever, melhor você se tornar, menos chance terá de fazer testes ruins.

    
por 13.10.2010 / 01:17
fonte
19

Uma tática é escrever o teste antes do código que ele testa e garantir que o teste falhe primeiro pelo motivo certo. Se você usar TDD , deverá obter pelo menos esse nível de testes.

Uma maneira mais exaustiva de testar a qualidade de um conjunto de testes é usar testes de mutação .

    
por 13.10.2010 / 04:13
fonte
4

Para # 1 e # 3: os testes de unidade não devem conter nenhuma lógica, se você fizer isso, provavelmente você está testando mais de uma coisa em seu teste de unidade. Uma prática recomendada para testes unitários é ter apenas um teste por unidade.

Veja este vídeo de Roy Osherove para saber mais sobre como para escrever bem os testes de unidade.

    
por 13.10.2010 / 02:29
fonte
3

Em termos de nº 1, acho que é uma boa ideia parear / rever o código para esse lado das coisas. É fácil fazer pressuposições ou simplesmente fazer as coisas erradas, mas se você tem que explicar o que seu teste está fazendo, qual é a questão, é mais provável que você perceba se estiver mirando no alvo errado.

    
por 13.10.2010 / 01:34
fonte
2

Deve haver um ponto em que alguém deve parar de tentar o teste de unidade. Deve saber quando traçar a linha. Devemos escrever casos de teste para testar casos de teste? E os novos casos de teste escritos para testar casos de teste? Como vamos testá-los?

if (0 > printf("Hello, world\n")) {
  printf("Printing \"Hello, world\" failed\n");
}

Editar: atualizado com a explicação sugerida pelo comentário.

    
por 13.10.2010 / 01:09
fonte
2

Olá.
Você tem que aplicativos:

  • Seu produto
  • Seu teste para esse produto.

Quando você está executando testes contra o seu produto, na verdade você não está envolvido no teste em si, mas na interação entre seu produto e seus testes. Se o teste falhar, não diz que o aplicativo tem um bug. Ele diz que a interação entre o produto e o teste não foi bem-sucedida . Agora é o seu trabalho para determinar o que deu errado. Pode ser:

  • o aplicativo não está se comportando como você esperava (essa expectativa é expressa em seu teste)
  • o aplicativo está se comportando corretamente, você não documentou esse comportamento corretamente (em seus testes)

Para mim, os testes que falham não são simples feedback, que isto e aquilo está errado . É um indicador que há inconsistência, e eu preciso examinar ambos para conferir queira deu errado. No final, sou responsável por verificar se o aplicativo está correto, os testes são apenas uma ferramenta para destacar áreas que podem valer a pena verificar.

Os testes estão apenas verificando algumas partes do aplicativo. Eu testo o aplicativo, eu testo os testes.

    
por 20.02.2011 / 20:16
fonte
2

Os testes não devem ser "inteligentes" o suficiente para abrigar bugs.

O código que você está escrevendo implementa um conjunto de especificações. (Se X, então Y, a menos que Z, caso em que Q, etc etc). Tudo o que o teste deve estar tentando realizar é determinar que X é realmente Y, a menos que Z, em cujo caso Q. Isso significa que tudo que um teste deve fazer é definir X e verificar Y.

Mas isso não cobre todos os casos, você provavelmente está dizendo, e você estaria certo. Mas se você tornar o teste "inteligente" o suficiente para saber que X deve apenas por Y, se não por Z, então basicamente você está reimplementando a lógica de negócios no teste. Isso é problemático por razões que entramos um pouco mais abaixo. Você não deve melhorar a cobertura do código fazendo o seu primeiro teste "mais inteligente", você deve adicionar um segundo teste estúpido que define X e Z e verifica Q. Dessa forma você terá dois testes, um que cobre o caso geral ( às vezes também conhecido como o caminho feliz) e um que cobre o caso de borda como um teste separado.

Existem várias razões para isso, em primeiro lugar, como você determina se um teste falho se deve a um erro na lógica de negócios ou a um erro nos testes? Obviamente, a resposta é que, se os testes forem tão simples quanto possível, é muito improvável que eles estejam abrigando bugs. Se você acha que seus testes precisam de testes, então você está testando errado .

Outras razões incluem que você está apenas replicando o esforço (como já mencionei, escrever um teste inteligente o suficiente para exercitar todas as possibilidades em um único teste é basicamente replicar a lógica de negócios que você está tentando testar) se os requisitos mudam, então os testes devem ser fáceis de mudar para refletir os novos requisitos, os testes servem como um tipo de documentação (eles são uma maneira formal de dizer qual é a especificação da unidade em teste), e assim por diante.

TL: DR: Se seus testes precisarem de testes, você está fazendo errado. Escreva testes burros .

    
por 13.03.2017 / 14:25
fonte
0

Não é uma resposta (não tenho o privilégio de comentar), mas queria saber se esqueceu outras razões para desenvolver casos de teste ...
Depois de descobrir todos os erros nos testes, você pode testar facilmente a sua regressão. Conjuntos de testes automatizados ajudariam a encontrar problemas mais cedo, antes da integração. As mudanças nos requisitos são relativamente mais fáceis de testar, pois as alterações podem se tornar mais novas, alterar a versão dos casos de teste mais antigos que passam e os casos mais antigos ficam com falhas.

    
por 20.02.2011 / 20:55
fonte
0

Resposta curta: O código de produção testa os testes .

Compare isso com o modelo crédito / débito usado em economia. A mecânica é muito simples - se o crédito difere do débito, há algo errado.

ele vale para testes de unidade - Se um teste falhar, isso indica que algo está errado. Pode ser o código de produção, mas também pode ser o código de teste! Esta última parte, se importante.

Observe que os erros do tipo (1) não podem ser encontrados por testes de unidade. Para evitar esse tipo de erro, você precisa de outras ferramentas.

    
por 27.02.2012 / 15:48
fonte