O teste de unidade de afirmação única não quebra o princípio DRY?

12

Sempre que escrevo testes de unidade, sempre tentei ter uma única declaração por teste para facilitar a depuração quando os testes falham. No entanto, ao seguir essa regra, sinto que estou constantemente copiando o mesmo código em cada teste e, com mais testes, fica mais difícil voltar a ler e manter.

O teste de afirmação única viola o DRY?

E existe uma boa regra a seguir para encontrar um bom equilíbrio, como ter apenas um teste por método ? *

* Sei que provavelmente não existe uma solução única para isso, mas existe uma maneira recomendada de abordar isso?

Korey Hinton
fonte
5
Você pode extrair o código que você copiar para métodos
Ismail Badawi
@IsmailBadawi parece uma boa ideia. Eu diria que esses métodos devem retornar uma instância do objeto de classe que eu estou testando
Korey Hinton
1
Você está criando algo em um determinado estado para ser testado? Isso soa como um acessório.
precisa
@DaveHillier sim, eu aprendi uma nova palavra hoje. Obrigado :)
Korey Hinton
depende de como você interpreta 1 afirmação por teste, se você quer dizer uma chamada de afirmação *, sim, se você também deseja garantir que os invariantes ainda permaneçam (depois extraia isso em um método) ou se existem vários efeitos que você pode ' teste t em uma única Assert (ou se você fez, então não seria claro o motivo da falha)
catraca aberração

Respostas:

14

Os testes de unidade adequados possuem uma convenção de nomenclatura que ajuda a identificar imediatamente o que falhou:

public void AddNewCustomer_CustomerExists_ThrowsException()

É por isso que você tem uma asserção por teste, para que cada método (e seu nome) corresponda à condição que você está afirmando.

Como você apontou corretamente, cada novo teste terá um código de configuração semelhante. Como em qualquer código, você pode refatorar o código comum em seu próprio método para reduzir ou eliminar a duplicação e tornar seu código mais SECO. Algumas estruturas de teste foram projetadas especificamente para permitir que você coloque esse código de instalação em um único local .

No TDD, nenhum teste é YAGNI, porque você escreve testes com base apenas no que você precisa que seu código faça. Se você não precisar, não fará o teste.

Robert Harvey
fonte
Refatorar em um único método parece bom. Se eu precisasse que uma instância da classe estivesse em um determinado estado, poderia criar e retornar uma nova instância desse objeto no método refatorado ou, como você sugere, usar os métodos fornecidos pela estrutura de teste para a configuração inicial do teste.
Korey Hinton
em seu último ponto, eu tenho certeza que eu poderia escrever testes para a funcionalidade que eu gosto o código de ter, em vez de funcionalidade que ele precisava
Joel B
5

O teste de afirmação única viola o DRY?

Não, mas promove violação.

Dito isto, um bom design orientado a objetos tende a sair pela janela para testes de unidade - principalmente por um bom motivo. É mais importante que os testes de unidade sejam isolados um do outro para que o teste possa ser interrogado isoladamente e, se necessário, corrigido com confiança para que você não faça outros testes. Basicamente, a correção e a legibilidade do teste são mais importantes que seu tamanho ou capacidade de manutenção.

Francamente, nunca fui fã da regra de uma afirmação por teste pelos motivos que você descreve: isso leva a muitos códigos clichê que são difíceis de ler, fáceis de enganar e difíceis de corrigir se você refatorar (o que leva você a refatorar menos).

Se uma função deve retornar uma lista de "foo" e "bar" para uma determinada entrada, mas em qualquer ordem, é perfeitamente bom usar dois assertivos para verificar se ambos estão no conjunto de resultados. O problema é quando um único teste verifica duas entradas ou dois efeitos colaterais e você não sabe qual das duas causou a falha.

Eu vejo isso como uma variação do Princípio da Responsabilidade Única: deve haver apenas uma coisa que pode causar uma falha no teste e, em um mundo ideal, essa mudança deve apenas quebrar um teste.

Mas no final, é uma troca. É mais provável que você gaste mais tempo mantendo todo o código colado da cópia ou passará mais tempo procurando as causas-raiz quando os testes podem ser interrompidos por várias fontes. Contanto que você escreva alguns testes, provavelmente não importa muito. Apesar do meu desprezo pelos testes de afirmação única, tenho tendência a errar ao lado de mais testes. Sua milhagem pode variar.

Telastyn
fonte
1
Para os testes, é mais importante ser DAMP do que DRY (frases descritivas e significativas).
Jörg W Mittag
2

Não. Parece que é exatamente assim que você faz. A menos que você tenha encontrado uma referência notável, onde eles alegam que essa é uma boa prática.

Use um acessório de teste (embora na terminologia do XUnit o conjunto de testes, a instalação e o desmontagem sejam o acessório), ou seja, algumas configurações ou exemplos que se apliquem a todos os seus testes.

Use métodos como você normalmente faria para estruturar seu código. Quando os testes de refatoração, o TDD vermelho-verde-refator usual não se aplica; em vez disso, aplica-se "Refatoração no vermelho". Isso é,

  1. deliberadamente quebrar seu teste,
  2. faça sua refatoração
  3. conserte seu teste

Dessa forma, você sabe que os testes ainda dão resultados positivos e negativos.

Existem vários formatos padrão para testes. Por exemplo, Organizar, Agir, Declarar ou Fornecer quando, Então (BDD) . Considere usar uma função separada para cada etapa. Você deve poder chamar a função para reduzir o clichê.

Dave Hillier
fonte