Junit4: Führt die BiMatcher-Hierarchie ein

Erstellt am 8. Feb. 2018  ·  9Kommentare  ·  Quelle: junit-team/junit4

Eine gute Funktion wäre die Einführung einer BiMatcher Hierarchie (analog zu org.hamcrest.Matcher , aber mit 2 Argumenten). Alternativ kann hierfür auch das Standard Comparator verwendet werden. Auch BiPredicate kann verwendet werden (dies bindet JUnit an Java-8, fügt aber eine standardmäßige UND/ODER/NICHT-Logik hinzu).
Ein paar Anmerkungen für alle weiteren Codes:

  • BiMatcher , BiPredicate und Comparator werden austauschbar verwendet.
  • Der gesamte Code ist nicht endgültig und nur eine allgemeine Idee.

Hauptmethoden zum Hinzufügen in der Assert Klasse:

  • assertThat(T expected, T actual, Comparator<T> biMatcher);
  • assertThat(String message, T expected, T actual, Comparator<T> biMatcher); (vielleicht nicht notwendig, siehe unten).
  • Mehrere assertArray() Methoden (siehe unten).

Die Motivation: Manchmal müssen Sie viele ähnliche Prüfungen gegen eine Reihe von Objekten durchführen. Bestehende Funktionalitäten erlauben dies, jedoch mit viel zusätzlichem Code (Schleifen und Bedingungen). Mit Comparator geht das mit weniger Code und mit höherer Flexibilität.

Echtes Beispiel (von dem aus ich tatsächlich über diese Funktion nachgedacht habe): Es muss getestet werden, ob alle Objekte im Array gleich oder nicht gleich sind (abhängig von einem booleschen Flag).

Mit den aktuellen JUnit-Fähigkeiten sieht es so aus:
kürzer:

for (int i = 0; i < elements.length - 1; i++) {
  if (checkSame) { // Same
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  } else { // Not same
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

bessere Leistung (aber wen interessiert die Leistung in Tests):

if (checkSame) { // Same
  for (int i = 0; i < elements.length - 1; i++) {
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  }
else { // Not same
  for (int i = 0; i < elements.length - 1; i++) {
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

Wir können auch eigene Comparator implementieren und assertTrue()/assertFalse() , aber der Code zum Erstellen von Komparatoren wird auch groß sein (es sei denn, wir verwenden Lambdas).

Mit neuem Ansatz sieht der Code für mich viel kürzer und sauberer aus, wie folgt:

Comparator<T> comparator = checkSame ? BiMatchers.same() : BiMatchers.notSame();
String message = checkSame ? "elements must be the same." : "elements must be not the same.";
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Um es noch kürzer zu machen, können wir Comparator mit der optionalen Eigenschaft message auf MessagedComparator , sodass JUnit es irgendwie von dort übernimmt. So was:

MessagedComparator<T> comparator = checkSame ? BiMatchers.same("elements must be the same.") : BiMatchers.notSame("elements must be not the same.");
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Die Folgen sind sehr weitreichend:
1) Die Klasse Assert wird im Allgemeinen sehr flexibel sein, da Sie ohne viel Code jeden Standard- oder eigenen Komparator verwenden können.
2) Als Ergebnis des Vorhergehenden können Lambdas leichter verwendet werden, um alle Bedingungen zu injizieren.
3) Zusätzliche Logikkaskadierung (AND, OR, NOT) kann out-of-the-box hinzugefügt werden (ähnlich wie org.hamcrest.CoreMatchers ). Derzeit ist für jedes neue Mini-Feature eine neue Methode erforderlich, zB assertNotSame() neben assertSame() usw. Oder wir brauchen wiederum assertTrue()/assertFalse() Methoden.
4) Die gesamte Assert Klasse kann in eine einheitliche Form umgestaltet werden. Nur ein Beispiel:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(message, expected, actual, BiMatchers.same())
}

public static void assertThat(String message, T expected, T actual, Comparator<T> biMatcher) {
...
}

oder wie schon erwähnt:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(expected, actual, BiMatchers.same(message))
}

public static void assertThat(T expected, T actual, MessagedComparator<T> biMatcher) {
...
}

5) assertArray() Methoden können hinzugefügt werden (also alte Methoden umgestaltet). Z.B:

public static void assertArrayEquals(boolean[] expecteds, boolean[] actuals) {
  assertArray(expecteds, actuals, BiMatchers.equals());
}

public static void assertArray(boolean[] expecteds, boolean[] actuals, Comparator<Boolean>) {
...
}

So können Sie zum Beispiel überprüfen, ob alle Elemente in 2 Arrays so einfach sind wie:

Assert.assertArray(array1, array2, BiMatchers.same());

Auch Array-Länge oder andere Prüfungen können separat gesteuert werden. Pseudocode:

Assert.assertArray(array1, array2, and(sameLength(), same()));

Alle 9 Kommentare

Danke, dass Sie dieses Thema angesprochen haben.

Ich würde es vorziehen, dass JUnit 4.x keine weiteren Assertions-DSLs hinzufügt. Es ist wirklich schwer, eine korrekte und flexible DSL zu bekommen, und ich bin mir nicht sicher, ob es sinnvoll ist, Zeit und Mühe dafür in JUnit aufzuwenden, wenn es gute Assertion-Frameworks von Drittanbietern wie Truth oder Fest gibt.

Außerdem sollten Funktionen, die Java 8 erfordern, zu http://github.com/junit-team/junit5 gehen

@gitIvanB Danke für das Öffnen des Problems. Wie @kcooney denke ich auch, dass dies am besten durch eine Assertionsbibliothek, z. B. AssertJ, gelöst werden könnte.

@kcooney , @marcphilipp , danke für den Hinweis. Sieht so aus, als ob die Verwendung von Assertion-Bibliotheken hier eine bewährte Methode ist.
Eine zusätzliche Frage. Kann ich als Faustregel verwenden, dass die Verwendung von Assert veraltet (oder nicht empfohlen) ist? Denken Sie insbesondere an zukünftige mögliche Upgrades von JUnit-4 auf JUnit-5.

@gitIvanB Die Frage ist etwas org.junit.Assert , bei Entwicklung gegen junit5 dann org.junit.jupiter.api.Assertions

Der empfohlene Ansatz besteht darin, Methoden statisch zu importieren, um zu vermeiden, dass in jeder Zeile Assert. ist.

@gitIvanB Sie sollten junit.framework.Assert definitiv nicht verwenden, aber org.junit.Assert ist in Ordnung. Wenn Sie ein Upgrade durchführen, können Sie eine IDE verwenden, um JUnit 4 in JUnit Jupiter-Assertionen zu konvertieren (IDEA unterstützt dies bereits). Der größte Unterschied besteht darin, dass der optionale Nachrichtenparameter in JUnit 4 an erster Stelle steht, in Jupiter jedoch zuletzt. Alternativ können Sie sich jetzt entscheiden, eine andere Assertion-Bibliothek zu verwenden und diese bei der Migration von Vintage zu Jupiter weiterhin zu verwenden.

@panchenko , @marcphilipp So wie ich es verstanden habe, ist das org.junit.Assert JUnit-4 versiegelt und wird nicht mit neuen Methoden angereichert. In JUnit-5 muss ich entweder org.junit.jupiter.api.Assertions (als Ersatz von org.junit.Assert ) oder eine Assertion-Lib verwenden.
Ich brauche etwas Zeit, um JUnit-5 zu lernen, aber auf den ersten Blick in org.junit.jupiter.api.Assertions sieht es so aus, als ob der Ansatz im Allgemeinen ähnlich wie bei org.junit.Assert . Es ist also eine große Chance, dass ich ein ähnliches Ticket für JUnit-5 erstellen muss :) Ich glaube, JUnit-5 sollte entweder vollwertige Assertionen bereitstellen oder vollständig an Assertion-Libs delegieren.

Die Philosophie von @gitIvanB JUnit besteht darin, ein gutes, erweiterbares Framework zum Schreiben von Tests für Java in Java bereitzustellen. Da es sich um ein erweiterbares Framework handelt, sehen wir oft, dass andere Open-Source-Projekte das Framework erweitern und/oder umfangreiche Testbibliotheken bereitstellen, die mit JUnit verwendet werden können.

Für Zusicherungen gibt es mehrere Projekte, die einen umfangreicheren Satz von Zusicherungen bereitstellen, manchmal auf erweiterbare Weise.
Es gibt beispielsweise Google Truth (https://github.com/google/truth), FEST (https://github.com/alexruiz/fest-assert-2.x), AssertJ (http://joel- costigliola.github.io/assertj/) und Hamcrest (http://hamcrest.org/JavaHamcrest/).

Da es so viele erstaunliche Assertion-Bibliotheken gibt, habe ich mich geweigert, neue Feature-Anfragen für org.junit.Assert anzunehmen. Ich würde es nicht als eingefroren betrachten (obwohl ich junit.framework.Assert eingefroren betrachten würde). Tatsächlich wird 4.13 assertThrows einführen. Aber da wir nie einen so reichhaltigen Satz von Behauptungen wie diese Projekte haben werden, fühlen wir uns wohl, die Grundlagen bereitzustellen.

Anders ausgedrückt haben sich gesunde Gemeinschaften um die Nutzung und Wartung dieser Projekte herum gebildet, daher denke ich, dass wir sie annehmen und unterstützen sollten.

Ich kann nicht für JUnit5 sprechen, aber ich kann mir vorstellen, dass die ursprünglichen Entwickler der Meinung waren, dass sie die nächste Generation von JUnit nicht ohne eine gute Grundlage von Assertionsmethoden veröffentlichen könnten (oder vielleicht den besten Weg fanden, um sicherzustellen, dass das neue Framework funktionsfähig ist und poliert war, JUnit5 mit JUnit5) zu testen. Neue Programmierpraktiken führten dazu, dass sie andere Entscheidungen darüber trafen, wie eine grundlegende Assertion-API aussehen würde als Kent, Erich und David, sodass Sie einige Unterschiede sehen werden. Aber Sie werden in JUnit wahrscheinlich nie einen so reichhaltigen Satz von Behauptungen sehen wie bei Hamcrest oder einer erweiterbaren DSL wie Truth.

Ich überlasse es dem JUnit5-Team zu entscheiden, welche Arten von Änderungen es in Betracht zieht. Wenn Sie das starke Gefühl haben, dass die
Methoden, die Sie vorschlagen, sind wichtig als Grundlage für das Schreiben guter Tests. Sie können dort gerne ein Problem erstellen.

Als wir mit der Arbeit an JUnit 5 (damals Codename "JUnit Lambda") begannen, besprachen wir den Umfang dessen, was wir erreichen wollten. Das Schreiben einer neuen Art von Assertion-Bibliothek wurde ausdrücklich nicht in den Anwendungsbereich fallen gelassen.

Oder, wie es im JUnit 5-Benutzerhandbuch heißt:

Obwohl die Assertion-Möglichkeiten von JUnit Jupiter für viele Testszenarien ausreichend sind, gibt es Zeiten, in denen mehr Leistung und zusätzliche Funktionen wie Matcher gewünscht oder benötigt werden. In solchen Fällen empfiehlt das JUnit-Team die Verwendung von Assertionsbibliotheken von Drittanbietern wie AssertJ, Hamcrest, Truth usw. Entwickler können daher die Assertionsbibliothek ihrer Wahl verwenden.

Es ist also auch nicht eingefroren, aber das Ziel ist ähnlich wie in JUnit 4, nämlich einen grundlegenden Satz von Assertionen bereitzustellen, um Benutzern den Einstieg zu erleichtern. Wir verwenden AssertJ sogar für unsere eigenen Unit-Tests.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen