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?

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.


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 .


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 .


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.


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


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.


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.