A adesão a uma afirmação por teste de consistência tola nesse caso?

10

Eu tenho uma classe que estou testando. A classe tem uma função:apply(List<IRule> rules, List<ITarget> targets);

Em um teste, quero garantir que cada destino tenha sido passado para uma regra, a la:

rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));

Parece-me que me limitar a uma única declaração de asserção seria bastante complicado . Estou correto nesta suposição, ou existe alguma outra maneira de afirmar que cada alvo foi, de fato, testado?

Wayne Werner
fonte
Eu posso ver os fiordes!
Ross Patterson

Respostas:

15

As três afirmações são essencialmente um teste. Você está testando o comportamento de um método em uma coleção, para garantir que cada item tenha sido um parâmetro para uma chamada específica (ou seja, que cada item tenha sido processado corretamente).

Configurar os dados três vezes e em três métodos diferentes é um desperdício e menos legível do que a alternativa de ter várias afirmações.

A única regra de afirmação é mais sobre fazer afirmações de tipos diferentes nos mesmos métodos (essencialmente testando coisas diferentes), o que realmente não se aplica nesse caso, em que você está testando um único comportamento.

Oded
fonte
3
De fato: a regra é mais uma afirmação lógica por teste de unidade. Você pode agrupá-los em um nível superior e afirmar que pode reutilizar em diferentes testes.
Laurent Bourgault-Roy
5

É minha convicção que esta regra de afirmativa por teste existe para manter seus testes focados em um problema. Se você testar 20 coisas em um teste, é realmente difícil dizer qual é a sua cobertura. Você sabe que está causando um problema quando não pode nomear o método de teste sem a palavra e nele. Por exemplo, se seu método de teste for nomeado com mais precisão como testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur(), provavelmente você está testando demais em um teste.

No seu caso, acho que não há problema em afirmar três vezes. Se você quiser fazer seu código mais legível, você pode extrair esses três afirma em um método chamado assertWasCalledOnTargets(...).

Daniel Kaplan
fonte
3

Para o seu exemplo em particular, você pode se safar da declaração de declaração "one" se fizer algo como:

foreach target in targets
{
     rule1.AssertWasCalled(fnord => fnord.Test(target))
}

É o que faço para evitar me sentir culpado por ter várias afirmações em um teste.

Jeff B
fonte
Eu já fiz isso antes. Não é um mau caminho a percorrer. É fácil de ler e você pode entender a natureza do que está fazendo.
CokoBWare
1

Também lutei com este.

O purista (em mim) insiste em uma afirmação por teste, para que eu saiba * exatamente * onde as coisas explodiram.

E então me encontro cortando / colando muito do mesmo código de configuração de teste redundante. Após a terceira ou quarta camada disso, você começa a dizer "Oi! Basta!"

Meu compromisso foi encontrar os aspectos que "nunca" quebram. E eu vou juntar essas peças e depois adicionar um novo elemento que pode quebrar. Só para esclarecer, colocar em camadas várias áreas voláteis em um teste seria uma violação desse compromisso.


fonte
11
Você deveria conferir Assume. Acabei de aprender sobre isso hoje.
Wayne Werner
1

Se o código de configuração target1for diferente do código de configuração target2, esse tipo de corte de esquina tende a eventualmente levar a um código de inicialização de teste excessivamente longo. Por sua vez, isso é uma bagunça ou acaba sendo refatorado e reutilizado. Se seus testes forem complexos o suficiente para justificá-los, provavelmente você está testando mais de uma coisa.

Se o código de configuração para cada destino for essencialmente o mesmo, dividir seu teste em vários testes individuais provavelmente será um exagero.

Se target1e target2são implementações diferentes da mesma interface, você deve adicionar um teste de unidade à interface (e permitir que sua estrutura de teste gere um teste para todas as implementações dessa interface).

Brian
fonte