Testes parametrizados - Quando e por que você os utiliza?

15

Recentemente, no trabalho, tivemos algumas diferenças de opinião em relação aos testes parametrizados . Normalmente usamos um estilo TDD (ou pelo menos tentamos), então eu entendo os benefícios dessa abordagem. No entanto, estou lutando para ver o ganho dos testes parametrizados. Para referência, trabalhamos em um serviço e suas bibliotecas são expostas por meio de uma interface RESTful.

O que eu vi até agora são testes que são, pelo menos, usando JUnit no Eclipse:

  • Sem detalhes - quando um teste falha, é muito difícil ver os parâmetros que causaram a falha
  • Muitas vezes complicado de criar
  • Tende a ser criado depois que o código foi escrito - estritamente não é uma desvantagem, como tal, mas as pessoas começam com testes parametrizados em mente quando iniciam um pedaço de código?

Se alguém tiver exemplos de onde eles são realmente úteis ou até mesmo boas dicas para usá-los, isso seria fantástico. Quero ter certeza de que não estou apenas sendo obstinado, porque pessoalmente não escolho usá-los e ver se eles são algo que devemos considerar fazer parte do nosso arsenal de testes.

neilprosser
fonte
1
O problema não está na idéia, mas na biblioteca desajeitada. Em C #, a sintaxe é muito mais amigável, quando você usa, por exemplo, MbUnit. Sim, é uma boa ideia. Adicione seu próprio código para facilitar esse processo - leia coisas de arquivos - o que funcionar. Veja também como o MsTest lida com isso.
Nós (Square) escrevemos Burst para abordar alguns desses problemas Parameterized. Ele geralmente adiciona menos clichê e deixa bem claro onde um teste falhou.
Daniel Lubarov 21/10

Respostas:

4

O problema ao testar qualquer software é que a complexidade explode rapidamente. O fato é que você não pode testar todas as combinações possíveis de parâmetros passadas para seus métodos. Phadke defende uma abordagem de Design de Experimentos (DOE), que permite a geração da lista provável de valores de parâmetros que precisam ser testados.

A idéia é que, mesmo que você não esteja testando exaustivamente, a maioria dos defeitos causa uma "região de falha" em vez de uma falha pontual isolada. A abordagem do DOE que Phadke defende usando matrizes ortogonais mostra o espaço dos parâmetros com precisão suficiente para atingir todas as possíveis regiões de falha.

Falhas isoladas provavelmente não serão identificadas, mas geralmente são menos que regiões de falha.

A abordagem DOE fornece uma maneira sistemática de escolher os valores dos parâmetros para variar.

Peter K.
fonte
O link fornecido está quebrado.
Josh Gust
1
@JoshGust Facilmente corrigido usando o Google. Obrigado pela atenção.
Peter K.
4

Eles podem ser úteis para garantir que seu código lide não apenas com o caminho feliz, mas também com os casos extremos. Depois que você souber que seu código funciona com variáveis ​​normais, parametrize o caso de teste e verifique se nulos e zeros, cadeias vazias, números grandes, cadeias longas, caracteres estranhos Unicode etc. também funcionam bem.

Ethel Evans
fonte
2

Existem pelo menos dois tipos de testes parametrizados, pelo menos na JUnit 4.8. São eles: Testes parametrizados ( @RunWith(Parameterized.class)), que requerem uma fonte de dados, que gera / lê configurações predefinidas de parâmetros, e Teorias ( @RunWith(Theories.class)), que, considerando um ou mais conjuntos possíveis de entradas por tipo de argumento, podem exercer a especificação de determinados métodos. Parece mais ou menos assim:

  • especifique alguns valores possíveis ( @DataPoints) para argumentos de string (como null, string vazia, string não vazia, string realmente longa)
  • especificar alguns valores possíveis ( @DataPoints) para argumentos classe Animal (como null, Dogexemplo, Catexemplo, Birdinstância)
  • prepare o @Theoryque aceita um Stringparâmetro e um Animalparâmetro. será executado com todas as combinações possíveis dos possíveis valores de parâmetros (no exemplo dado, isso seria 4x4 = 16 combinações, incluindo ( null, null))
  • se o método em teste não puder aceitar alguma combinação, use Assume.assumeThatimportações estáticas para filtrar combinações inválidas (por exemplo, quando você quiser verificar o comportamento do método em busca de cadeias não vazias, uma das primeiras linhas seria "supor que não seja nulo"

Como foi escrito antes - não faz sentido testar todas as combinações possíveis de todos os métodos (explode conjuntos de testes, imagine testar um método com 5 parâmetros, cada um com apenas 5 valores possíveis: 5 ** 5 -> mais de 3000 execuções de teste !), mas para métodos de missão crítica (como métodos de API) eu o incentivaria, apenas por estar no lado seguro ...

Adam Hepner
fonte
1

Exemplo genérico:

  • Métodos com argumentos de string. Use testes parametrizados para testar diferentes entradas e suas saídas esperadas. É muito mais prático ter uma lista de pares (entrada, esperado) do que escrever um TC para cada par.

  • Aplique o mesmo cenário em argumentos diferentes. Nós temos um cenário que trabalha com o Animalobjeto ea ter um monte de subclasses tais como Dog, Cat, Bird. Crie uma lista dos animais disponíveis e teste o cenário neles.

Concreto para webservice:

  • No exemplo de argumentos de cadeia acima. Teste o que acontece com argumentos diferentes do mesmo tipo, mas com valores diferentes.
Victor Hurdugaci
fonte
0

Testes parametrizados funcionam bem para testar funções / recursos que possuem entrada simples quando você deseja testar uma variedade de entradas.

Eles não funcionam bem para testar diferentes funcionalidades e entradas complexas. Eles não devem ser usados ​​como uma estrutura de conveniência para escrever menos código.

Cirem
fonte
1
Por que os parâmetros não devem ser usados ​​como uma conveniência para escrever menos código? Não há grande virtude em fornecer uma lista exaustiva de um grande conjunto de casos de teste.
Jonathan Eunice
1
Como sua resposta fornece mais informações do que as outras 5 respostas?
Adam Zuckerman
-2

Um caso em que eu uso muitos testes parametrizados de maneira TDD-ish é escrever analisadores - posso começar com uma lista de entrada e saída esperada e depois escrever o código para que ele passe em todos os casos de teste.

Mas já vi alguns horrores de testes parametrizados. Não, Virginia, sua suíte de testes não deve precisar de testes de unidade próprios.

Wyatt Barnett
fonte
1
Os testes idealmente parametrizados devem ter a forma "o item (n) na saída real corresponde ao item (n) na saída esperada" ou similar e, nesse caso, nenhum teste é necessário. Mas, para qualquer coisa mais complexa, eu preferiria ver um ou dois testes parametrizados com seus próprios casos de teste do que o habitual "meu código de teste (obviamente) está obviamente correto". Se isso fosse verdade, você não estaria escrevendo casos de teste. Obviamente, é possível exagerar na complexidade e não estou argumentando que não há linha, mas acho que há casos em que testar testes é uma boa idéia.