Por que devo usar o Hamcrest-Matcher e assertThat () em vez do tradicional assertXXX () - Métodos

153

Quando olho para os exemplos na classe Assert JavaDoc

assertThat("Help! Integers don't work", 0, is(1)); // fails:
// failure message:
// Help! Integers don't work
// expected: is <1> 
// got value: <0>
assertThat("Zero is one", 0, is(not(1))) // passes

Não vejo uma grande vantagem, digamos assertEquals( 0, 1 ).

Talvez seja bom para as mensagens se as construções ficarem mais complicadas, mas você vê mais vantagens? Legibilidade?

Peter Kofler
fonte

Respostas:

172

Não há grande vantagem para os casos em assertFooque existe um que corresponde exatamente à sua intenção. Nesses casos, eles se comportam quase da mesma forma.

Mas quando você chega a verificações um pouco mais complexas, a vantagem se torna mais visível:

assertTrue(foo.contains("someValue") && foo.contains("anotherValue"));

vs.

assertThat(foo, hasItems("someValue", "anotherValue"));

Pode-se discutir qual deles é mais fácil de ler, mas, quando a declaração falhar, você receberá uma boa mensagem de erro assertThat, mas apenas uma quantidade mínima de informações assertTrue.

assertThatlhe dirá qual foi a afirmação e o que você obteve. assertTruesó lhe dirá que você chegou falseonde esperava true.

Joachim Sauer
fonte
Eu também tinha essa pergunta no fundo da minha mente. Obrigado, nunca pensei nisso dessa maneira.
wheaties
1
Também ajuda na "regra" de uma afirmação por teste e combina mais facilmente com as especificações no estilo BDD.
Nils Wloka
2
E separa o mecanismo de asserção da condição (que é o que leva a melhores mensagens de erro).
steved
2
O exemplo é implausível, pois quase ninguém usaria um assertTruecom um &&. Separá-lo em duas condições torna a causa do problema óbvia, mesmo no JUnit. Não me interpretem mal; Eu concordo com você, eu apenas não gosto do seu exemplo.
Maaartinus 11/08
48

As notas de versão do JUnit para a versão 4.4 (onde foi introduzida) apresentam quatro vantagens:

  • Mais legível e tipável: essa sintaxe permite pensar em termos de sujeito, verbo, objeto (asser "x é 3") em vez de assertEquals , que usa verbo, objeto, sujeito (asser "é igual a 3 x")
  • Combinações: qualquer declaração de correspondência s pode ser negada ( não ), combinada ( ou (s) .ou (t) ), mapeada para uma coleção ( cada ), ou usada em combinações personalizadas ( afterFiveSeconds (s) )
  • Mensagens de falha legíveis. (...)
  • Correspondentes personalizados. Ao implementar a interface do Matcher , você pode obter todos os benefícios acima para suas próprias asserções personalizadas.

Argumentação mais detalhada do cara que criou a nova sintaxe: aqui .

Manur
fonte
39

Basicamente, para aumentar a legibilidade do código .

Além de hamcrest, você também pode usar as afirmações do fest . Eles têm algumas vantagens sobre o hamcrest , como:

Alguns exemplos

import static org.fest.assertions.api.Assertions.*;

// common assertions
assertThat(yoda).isInstanceOf(Jedi.class);
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron);
assertThat(frodo).isIn(fellowshipOfTheRing);
assertThat(sauron).isNotIn(fellowshipOfTheRing);

// String specific assertions
assertThat(frodo.getName()).startsWith("Fro").endsWith("do")
                           .isEqualToIgnoringCase("frodo");

// collection specific assertions
assertThat(fellowshipOfTheRing).hasSize(9)
                               .contains(frodo, sam)
                               .excludes(sauron);


// map specific assertions (One ring and elves ring bearers initialized before)
assertThat(ringBearers).hasSize(4)
                       .includes(entry(Ring.oneRing, frodo), entry(Ring.nenya, galadriel))
                       .excludes(entry(Ring.oneRing, aragorn));

17 de outubro de 2016 Atualização

O Fest não está mais ativo, use o AssertJ .

Igor Popov
fonte
4
Fest parece ter morrido, mas o garfo AssertJ está muito vivo.
Amedee Van Gasse
18

Uma justificativa muito básica é que é difícil atrapalhar a nova sintaxe.

Suponha que um valor específico, foo, seja 1 após um teste.

assertEqual(1, foo);

--OU--

assertThat(foo, is(1));

Com a primeira abordagem, é muito fácil esquecer a ordem correta e digitá-la ao contrário. Então, em vez de dizer que o teste falhou porque esperava 1 e obteve 2, a mensagem é invertida. Não é um problema quando o teste passa, mas pode causar confusão quando o teste falha.

Com a segunda versão, é quase impossível cometer esse erro.

Andy Davis
fonte
... e quando o Eclipse relatar uma falha de asserção, se você colocar os argumentos de maneira errada no assertThat tradicional (), o erro não fará sentido.
Sridhar Sarnobat
9

Exemplo:

assertThat(5 , allOf(greaterThan(1),lessThan(3)));
//  java.lang.AssertionError:
//  Expected: (a value greater than <1> and a value less than <3>)
//       got: <5>
assertTrue("Number not between 1 and 3!", 1 < 5 && 5 < 3);
//  java.lang.AssertionError: Number not between 1 and 3!
  1. você pode tornar seus testes mais específicos
  2. você obtém uma exceção mais detalhada, se os testes falharem
  3. mais fácil de ler o teste

btw: você também pode escrever texto no assertXXX ...

MartinL
fonte
1
Melhor ainda, deixaria de fora o argumento da string no assertThatcaso, porque a mensagem que você recebe automaticamente é igualmente informativa: "Esperado: (um valor maior que <1> e menor que <3>)"
MatrixFrog
Sim você está certo. Eu edito minha resposta. Originalmente, quero usar os dois (Matcher) .e (Matcher), mas não funcionou.
MartinL
3
assertThat(frodo.getName()).isEqualTo("Frodo");

Está perto da linguagem natural.

Leitura mais fácil, código de análise mais fácil. O programador passa mais tempo analisando o código do que escrevendo um novo. Portanto, se o código for fácil de analisar, o desenvolvedor deve ser mais produtivo.

Código PS deve ser um livro bem escrito. Código auto-documentado.

user4515828
fonte
4
OK e…? Eu recomendo apoiar seu argumento explicando por que isso é uma coisa boa.
Nathan Tuggy
0

há vantagens em afirmarThat over assertEquals -
1) mais legível
2) mais informações sobre falha
3) erros de tempo de compilação - em vez de erros em tempo de execução
4) flexibilidade nas condições de teste de gravação
5) portátil - se você estiver usando hamcrest - você pode usar jUnit ou TestNG como a estrutura subjacente.

samshers
fonte