Können Sie AssertJ assertThat eine benutzerdefinierte Nachricht hinzufügen?

90

Wir haben eine Testsuite, die hauptsächlich JUnit-Assertions mit Hamcrest-Matchern verwendet. Einer unserer Mitarbeiter begann mit AssertJ zu experimentieren und beeindruckte die Leute mit seiner Syntax, Flexibilität und Deklarativität. JUnit bietet eine Funktion, für die ich in AssertJ kein Äquivalent finden kann: Hinzufügen einer benutzerdefinierten Assert-Fehlermeldung.

Wir vergleichen häufig Objekte, die nicht für die menschliche Lesbarkeit ausgelegt sind und zufällig erscheinende IDs oder UUIDs haben, und es ist unmöglich, anhand der darin enthaltenen Daten zu erkennen, wie sie aussehen sollen. Dies ist eine unvermeidbare Situation für unsere Codebasis. Leider besteht ein Teil des Zwecks darin, Daten zwischen anderen Diensten abzubilden, ohne unbedingt zu verstehen, was sie sind.

In JUnit stellt die assertThatMethode eine Version mit einem String reasonParameter vor dem Parameter Matcher<T>bereit. Dies macht es trivial, eine kurze Debug-Zeichenfolge hinzuzufügen, die etwas Licht in das Problem bringt, beispielsweise was der Vergleich für einen Menschen bedeuten sollte.

AssertJ hingegen bietet eine Vielzahl verschiedener generischerstatic assertThat Methoden, die eine Form der Schnittstelle Assert oder eine seiner vielen implementierenden Klassen zurückgeben. Diese Schnittstelle bietet keine Standardmethode zum Festlegen einer benutzerdefinierten Nachricht, die bei Fehlern enthalten sein soll.

Gibt es eine Möglichkeit, diese Funktionalität von der AssertJ-API oder einer ihrer Erweiterungen abzurufen, ohne für jeden Assert-Typ, dem wir Nachrichten hinzufügen möchten , eine benutzerdefinierte Assert-Klasse erstellen zu müssen?

Patrick M.
quelle

Antworten:

137

Und auf klassische Weise fand ich, wonach ich suchte, kurz nachdem ich die Frage gestellt hatte. Hoffentlich erleichtert dies der nächsten Person das Auffinden, ohne vorher wissen zu müssen, wie es heißt. Die magische Methode ist die täuschend kurze Bezeichnung as, die Teil einer anderen Schnittstelle ist, die Folgendes AbstractAssertimplementiert: Beschreibbar , nicht die Basis-Assert-Schnittstelle.

public S as(String description, Object... args)

Legt die Beschreibung dieses Objekts fest, das die String.format(String, Object...)Syntax unterstützt .
Beispiel:

try {
  // set a bad age to Mr Frodo which is really 33 years old.
  frodo.setAge(50);
  // you can specify a test description with as() method or describedAs(), it supports String format args
  assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(33);
} catch (AssertionError e) {
  assertThat(e).hasMessage("[check Frodo's age] expected:<[33]> but was:<[50]>");
}

Wo diese Zeichenfolge im Catch-Block in Anführungszeichen hasMessagesteht, wird in Ihrem Unit-Test-Ausgabeprotokoll angezeigt, wenn die Zusicherung fehlschlägt.


Ich fand dies, indem ich den failWithMessageHelfer auf der benutzerdefinierten Assert-Seite bemerkte, die in der Frage verlinkt ist. Das JavaDoc für diese Methode weist darauf hin, dass es geschützt ist, sodass es von Anrufern nicht zum Festlegen einer benutzerdefinierten Nachricht verwendet werden kann. Der asHelfer wird jedoch erwähnt :

Darüber hinaus berücksichtigt diese Methode jede Beschreibung, die mit einer as(String, Object...)vom Benutzer definierten oder überschriebenen Fehlermeldung festgelegt wurde overridingErrorMessage(String, Object...).

... und der overridingErrorMessage- Helfer, der die Standard-AssertJ- expected: ... but was:...Nachricht vollständig durch die neue bereitgestellte Zeichenfolge ersetzt.

Auf der AssertJ-Homepage wird keiner der Helfer erwähnt, bis auf der Seite mit den Funktionshighlights Beispiele für den asHelfer im Abschnitt " Soft Assertions " aufgeführt sind, aber nicht direkt beschrieben werden, was er tut.

Patrick M.
quelle
22

So fügen Sie der Antwort von Patrick M eine weitere Option hinzu:

Anstatt zu verwenden Descriptable.as, können Sie auch Folgendes verwenden AbstractAssert.withFailMessage():

try {
  // set a bad age to Mr Frodo which is really 33 years old.
  frodo.setAge(50);
  // you can specify a test description via withFailMessage(), supports String format args
  assertThat(frodo.getAge()).
    withFailMessage("Frodo's age is wrong: %s years, difference %s years",
      frodo.getAge(), frodo.getAge()-33).
    isEqualTo(33);
} catch (AssertionError e) {
  assertThat(e).hasMessage("Frodo's age is wrong: 50 years, difference 17 years");
}

Der Unterschied zur Verwendung Descriptable.asbesteht darin, dass Sie die vollständige Kontrolle über die benutzerdefinierte Nachricht haben - es gibt kein "erwartet" und "aber war".

Dies ist nützlich, wenn die tatsächlich getesteten Werte für die Darstellung nicht nützlich sind. Mit dieser Methode können Sie stattdessen andere oder möglicherweise berechnete Werte oder gar keine anzeigen.


Beachten Sie, dass Sie genau wie Descriptable.asSie withFailMessage() vor tatsächlichen Behauptungen anrufen müssen - andernfalls funktioniert es nicht, da die Behauptung zuerst ausgelöst wird. Dies wird im Javadoc vermerkt.

sleske
quelle
2
"Sie müssen withFailMessage () aufrufen, bevor Sie tatsächlich behaupten", danke, das hat mich gestolpert. Die Reihenfolge der Berufung withFailMessageMaterie; Ich mag AssertJ, aber das ist scheiße.
Abhijit Sarkar
0

Verwenden Sie die eingebaute as()Methode in AssertJ. Zum Beispiel:

 assertThat(myTest).as("The test microservice is not active").isEqualTo("active");
Testilla
quelle