Pourquoi devrais-je utiliser Hamcrest-Matcher et assertThat () au lieu du traditionnel assertXXX () - Méthodes

153

Quand je regarde les exemples de la 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

Je ne vois pas un grand avantage sur, disons que, assertEquals( 0, 1 ).

C'est bien peut-être pour les messages si les constructions deviennent plus compliquées mais voyez-vous plus d'avantages? Lisibilité?

Peter Kofler
la source

Réponses:

173

Il n'y a pas de gros avantage pour les cas où un assertFooexiste qui correspond exactement à votre intention. Dans ces cas, ils se comportent presque de la même manière.

Mais lorsque vous arrivez à des contrôles un peu plus complexes, l'avantage devient plus visible:

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

contre.

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

On peut discuter de celui qui est le plus facile à lire, mais une fois que l'assertion échoue, vous obtiendrez un bon message d'erreur assertThat, mais seulement une quantité très minimale d'informations assertTrue.

assertThatvous dira quelle était l'affirmation et ce que vous avez obtenu à la place. assertTruevous dira seulement que vous êtes arrivé falselà où vous vous attendiez true.

Joachim Sauer
la source
J'avais cette question aussi au fond de mon esprit. Merci, je n'y ai jamais pensé de cette manière.
Wheaties
1
Il facilite également la "règle" d'une assertion par test et se fond plus facilement avec les spécifications de style BDD.
Nils Wloka
2
Et il sépare le mécanisme d'assertion de la condition (ce qui conduit aux meilleurs messages d'erreur).
SteveD
2
L'exemple est peu plausible car presque personne n'utiliserait un single assertTrueavec un &&. Le séparer en deux conditions rend la cause du problème évidente même dans JUnit. Ne vous méprenez pas; Je suis d'accord avec vous, je n'aime pas votre exemple.
maaartinus
48

Les notes de publication de JUnit pour la version 4.4 (où il a été introduit) présentent quatre avantages:

  • Plus lisible et typable: cette syntaxe permet de penser en termes de sujet, verbe, objet (assert "x is 3") plutôt que assertEquals , qui utilise verbe, objet, sujet (assert "equals 3 x")
  • Combinaisons: toute instruction de correspondance peut être annulée ( pas (s) ), combinée ( soit (s) .ou (t) ), mappée à une collection ( chacune (s) ), ou utilisée dans des combinaisons personnalisées (après cinq secondes (s) )
  • Messages d'échec lisibles. (...)
  • Matchers personnalisés. En mettant en œuvre la matcher l' interface vous - même, vous pouvez obtenir tous les avantages ci - dessus pour vos propres affirmations personnalisées.

Argumentation plus détaillée du type qui a créé la nouvelle syntaxe: ici .

Manur
la source
39

Fondamentalement, pour augmenter la lisibilité du code .

Outre hamcrest, vous pouvez également utiliser les assertions fest . Ils présentent quelques avantages par rapport à hamcrest tels que:

Quelques exemples

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));

Mise à jour du 17 octobre 2016

Fest n'est plus actif, utilisez AssertJ à la place.

Igor Popov
la source
4
Fest semble être mort, mais la fourchette AssertJ est bien vivante.
Amedee Van Gasse
18

Une justification très basique est qu'il est difficile de gâcher la nouvelle syntaxe.

Supposons qu'une valeur particulière, foo, devrait être 1 après un test.

assertEqual(1, foo);

--OU--

assertThat(foo, is(1));

Avec la première approche, il est très facile d'oublier l'ordre correct et de le saisir à l'envers. Alors plutôt que de dire que le test a échoué parce qu'il attendait 1 et obtenait 2, le message est inversé. Pas de problème lorsque le test réussit, mais peut prêter à confusion lorsque le test échoue.

Avec la deuxième version, il est presque impossible de faire cette erreur.

Andy Davis
la source
... et quand Eclipse signale un échec d'assertion, si vous mettez les arguments dans le mauvais sens dans le traditionnel assertThat (), l'erreur n'a pas de sens.
Sridhar Sarnobat
9

Exemple:

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. vous pouvez rendre vos tests plus particuliers
  2. vous obtenez une exception plus détaillée si les tests échouent
  3. plus facile à lire le test

btw: vous pouvez aussi écrire du texte dans assertXXX ...

MartinL
la source
1
Mieux encore, je laisserais de côté l'argument de chaîne dans le assertThatcas, car le message que vous recevez automatiquement est tout aussi informatif: "Attendu: (une valeur supérieure à <1> et une valeur inférieure à <3>)"
MatrixFrog
Oui, tu as raison. Je modifie ma réponse. À l'origine, je veux utiliser à la fois (Matcher) et (Matcher) mais cela n'a pas fonctionné.
MartinL
3
assertThat(frodo.getName()).isEqualTo("Frodo");

Est proche du langage naturel.

Code plus facile à lire et à analyser. Le programmeur passe plus de temps à analyser le code qu'à en écrire un nouveau. Donc, si le code est facile à analyser, le développeur devrait être plus productif.

Le code PS doit être un livre aussi bien écrit. Code auto-documenté.

utilisateur4515828
la source
4
OK et…? Je recommande d'appuyer votre argument en expliquant pourquoi c'est une bonne chose.
Nathan Tuggy
0

il y a des avantages à affirmer que par rapport à assertEquals -
1) plus lisible
2) plus d'informations sur l'échec
3) des erreurs de temps de compilation - plutôt que des erreurs d'exécution
4) flexibilité avec l'écriture des conditions de test
5) portable - si vous utilisez hamcrest - vous pouvez utiliser jUnit ou TestNG comme cadre sous-jacent.

samshers
la source