Warum sollte ich Hamcrest-Matcher und assertThat () anstelle der herkömmlichen assertXXX () - Methoden verwenden?

153

Wenn ich mir die Beispiele in der Assert-Klasse JavaDoc ansehe

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

Ich sehe keinen großen Vorteil gegenüber, sagen wir mal assertEquals( 0, 1 ).

Es ist vielleicht schön für die Nachrichten, wenn die Konstrukte komplizierter werden, aber sehen Sie mehr Vorteile? Lesbarkeit?

Peter Kofler
quelle

Antworten:

172

Es gibt keinen großen Vorteil für Fälle, in denen eine assertFooexistiert, die genau Ihrer Absicht entspricht. In diesen Fällen verhalten sie sich fast gleich.

Wenn Sie jedoch zu etwas komplexeren Prüfungen kommen, wird der Vorteil deutlicher:

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

vs.

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

Man kann diskutieren, welche davon leichter zu lesen ist, aber sobald die Bestätigung fehlschlägt, erhalten Sie eine gute Fehlermeldung assertThat, aber nur eine sehr geringe Menge an Informationen assertTrue.

assertThatIch werde Ihnen sagen, was die Behauptung war und was Sie stattdessen bekommen haben. assertTrueIch werde Ihnen nur sagen, dass Sie dort angekommen sind, falsewo Sie es erwartet haben true.

Joachim Sauer
quelle
Ich hatte diese Frage auch im Hinterkopf. Danke, ich habe nie so darüber nachgedacht.
Wheaties
1
Es hilft auch bei der "Regel" einer Behauptung pro Test und lässt sich leichter mit BDD-Spezifikationen kombinieren.
Nils Wloka
2
Und es trennt den Assertionsmechanismus von der Bedingung (was zu den besseren Fehlermeldungen führt).
SteveD
2
Das Beispiel ist unplausibel, da kaum jemand eine Single assertTruemit einem verwenden würde &&. Die Aufteilung in zwei Bedingungen macht die Ursache des Problems selbst in JUnit offensichtlich. Versteh mich nicht falsch; Ich stimme dir zu, ich mag dein Beispiel einfach nicht.
Maaartinus
48

Die JUnit Release Notes für Version 4.4 (wo es eingeführt wurde) Zustand vier Vorteile:

  • Lesbarer und typisierbarer: Mit dieser Syntax können Sie in Bezug auf Subjekt, Verb, Objekt ( Assert "x ist 3") denken und nicht in AssertEquals , das Verb, Objekt, Subjekt verwendet ( Assert "entspricht 3 x").
  • Kombinationen: Alle Matcher-Anweisungen können negiert ( nicht (s) ), kombiniert ( entweder (s) .oder (t) ), einer Sammlung ( jeweils (s) ) zugeordnet oder in benutzerdefinierten Kombinationen ( afterFiveSeconds (s)) verwendet werden. )
  • Lesbare Fehlermeldungen. (...)
  • Benutzerdefinierte Matcher. Indem Sie die Matcher- Oberfläche selbst implementieren , können Sie alle oben genannten Vorteile für Ihre eigenen benutzerdefinierten Zusicherungen nutzen.

Detailliertere Argumentation von dem Typ, der die neue Syntax erstellt hat: hier .

Manur
quelle
39

Grundsätzlich zur Verbesserung der Lesbarkeit des Codes .

Neben Hamcrest können Sie auch die Fest-Behauptungen verwenden . Sie haben einige Vorteile gegenüber Hamcrest wie:

Einige Beispiele

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. Oktober 2016 Update

Fest ist nicht mehr aktiv, benutze stattdessen AssertJ .

Igor Popov
quelle
4
Fest scheint gestorben zu sein, aber die Gabel AssertJ ist sehr lebendig.
Amedee Van Gasse
18

Eine sehr grundlegende Rechtfertigung ist, dass es schwierig ist, die neue Syntax durcheinander zu bringen.

Angenommen, ein bestimmter Wert, foo, sollte nach einem Test 1 sein.

assertEqual(1, foo);

--ODER--

assertThat(foo, is(1));

Beim ersten Ansatz ist es sehr leicht, die richtige Reihenfolge zu vergessen und rückwärts einzugeben. Anstatt zu sagen, dass der Test fehlgeschlagen ist, weil er 1 erwartet und 2 erhalten hat, ist die Nachricht rückwärts. Kein Problem, wenn der Test bestanden wird, kann aber zu Verwirrung führen, wenn der Test fehlschlägt.

Mit der zweiten Version ist es fast unmöglich, diesen Fehler zu machen.

Andy Davis
quelle
... und wenn Eclipse einen Assertionsfehler meldet, macht der Fehler keinen Sinn, wenn Sie die Argumente im traditionellen assertThat () falsch herum platzieren.
Sridhar Sarnobat
9

Beispiel:

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. Sie können Ihre Tests genauer gestalten
  2. Sie erhalten eine detailliertere Ausnahme, wenn Tests fehlschlagen
  3. einfacher den Test zu lesen

Übrigens: Sie können auch Text in assertXXX schreiben ...

MartinL
quelle
1
Besser noch, ich würde das String-Argument in diesem assertThatFall
weglassen
Ja, du hast recht. Ich bearbeite meine Antwort. Ursprünglich möchte ich beide (Matcher) .und (Matcher) verwenden, aber es hat nicht funktioniert.
MartinL
3
assertThat(frodo.getName()).isEqualTo("Frodo");

Ist nah an der natürlichen Sprache.

Einfacher zu lesen, Code einfacher zu analysieren. Programer verbringen mehr Zeit mit der Analyse von Code als mit dem Schreiben von neuem Code. Wenn Code einfach zu analysieren ist, sollte der Entwickler produktiver sein.

PS-Code sollte als gut geschriebenes Buch sein. Selbst dokumentierter Code.

user4515828
quelle
4
OK und…? Ich empfehle, Ihre Argumentation zu unterstützen, indem Sie erklären, warum das eine gute Sache ist.
Nathan Tuggy
0

Es gibt Vorteile gegenüber assertEquals -
1) besser lesbar
2) mehr Informationen zum Fehler
3) Kompilierungszeitfehler - anstatt Laufzeitfehler
4) Flexibilität beim Schreiben von Testbedingungen
5) portabel - wenn Sie hamcrest verwenden, können Sie jUnit verwenden oder TestNG als zugrunde liegendes Framework.

samshers
quelle