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?

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.


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 .


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 .


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.


... 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 ...


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.


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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.