Junit4: Verbesserung: BigDecimal-Unterstützung für assertEquals()

Erstellt am 25. März 2010  ·  27Kommentare  ·  Quelle: junit-team/junit4

Die Verwendung von JUnit zum Testen von BigDecimal-Werten ist immer ein wunder Punkt. Dies liegt daran, dass BigDecimal die Genauigkeit mit equals() berücksichtigt, sie jedoch in CompareTo() ignoriert. Der beste Weg, dies zu handhaben, wäre eine neue assertEquals-Methode, mit der die Genauigkeit optional ausgewertet werden kann. Sie können auch eine alternative Methode hinzufügen, die eine Nachricht akzeptiert:

public static void assertEquals(BigDecimal erwartet, BigDecimal aktuell, boolesche PrecisionMatters) {
if (precisionMatters) {
Assert.assertEquals(erwartet, tatsächlich);
} anders {
Assert.assertEquals(0, erwartet.compareTo(tatsächlich));
}
}

feature

Hilfreichster Kommentar

Haben Sie versucht, comparesEqualTo ?

Alle 27 Kommentare

Wäre eine einfache Sache, als Gabel oder Patch zusammenzustellen; Gerne mache ich das ggf.

Ich hätte lieber eine assertNumericallyEqualTo-Assertion als ein boolesches Flag, das an assertEquals übergeben wird.

Das ist ein guter Name. Ich würde es zu assertNumericallyEquals() verkürzen.

Obwohl ich dem zustimme, bin ich mir nicht sicher, ob eine andere Assert-Methode mit einem anderen Namen wirklich dazu beitragen wird, die Verwirrung zu beseitigen, insbesondere bei Leuten, die sich des Unterschieds überhaupt nicht bewusst sind oder das Problem selbst nicht wirklich kennen. Ich meine, wenn ich diese Ausgabe nicht gelesen hätte, hätte ich assertEquals() für BigDecimal . Im Allgemeinen würde es tatsächlich wie beworben funktionieren – es würde genau so funktionieren, wie BigDecimal#equals() funktioniert. Ich würde sogar argumentieren, dass dies eine gute Sache ist – es zwingt jemanden zu erkennen, dass BigDecimal#equals() sowohl Wert als auch Maßstab vergleicht, dann war das vielleicht nicht das, was er erreichen wollte – obwohl ich es in anderen Fällen postuliere _ist_. Ich meine, in einigen Fällen möchten wir überprüfen, ob der von einer Methode zurückgegebene tatsächliche Wert _exactly_ 'gleich' dem erwarteten Wert ist (nicht nur logisch/numerisch gleich). Anders ausgedrückt: Was bietet assertNumericallyEquals() (abgesehen von der Kürze), was assertEquals(0, actual.compareTo(expected)) nicht bietet? Persönlich würde ich wahrscheinlich einen Hamcrest-Matcher erstellen und assertThat(actual, isNumericallyEqualTo(expected)) wenn ich ihn oft genug benötige – außerdem kann er überall verwendet werden, wo Hamcrest-Matcher verwendet werden können (unter anderem Datenvalidierung).

Entschuldigung für das späte Wiegen, aber meine persönliche Meinung ist der von Alistair nahe.

Anders ausgedrückt: Was bietet assertNumericallyEquals() (abgesehen von der Kürze), was assertEquals(0, actual.compareTo(expected)) nicht bietet?

Kommuniziert die Absicht klarer? Der Hamcrest-Matcher-Ansatz ist für mich in Ordnung.

Geoffrey,

Wollen Sie damit sagen, dass es Ihnen gut geht, diesen Matcher für Ihr eigenes Projekt zu schreiben, oder dass Sie möchten, dass er mit Hamcrest geliefert wird? Oder JUnit, aber nicht Hamcrest?

Einige oder alle der oben genannten - die meisten Projekte, die ich schreibe, haben am Ende einige benutzerdefinierte Hamcrest-Matcher. Häufige Fälle von Hamcrest und/oder JUnit abgedeckt zu haben, spart ein wenig Zeit, aber dies war auch kein sehr häufiger Fall für mich.

Ein kleiner Punkt zu weniger nützlichen Fehlermeldungen.. Ich habe gerade meine Assert.assertEquals-Aufrufe in Assert.assertTrue umgewandelt, da beim Vergleich von BigDecimals mit Assert.assertEquals Trefferfehler aufgetreten sind. Natürlich scheitern jetzt meine Tests mit einer Art "Boolescher Test fehlgeschlagen"-Fehler, ohne mir zu sagen, was die Werte waren. Auf die gleiche Weise würde assertEquals(0, current.compareTo(expected)) zB "expected 0 but got: 1" protokollieren, wenn eine weitaus nützlichere Fehlermeldung von assertNumericallyEquals(actual, Expected) wäre "erwartet 12.45 aber got : 123" (die tatsächlichen Werte der Argumente 'tatsächlich' und 'erwartet').

http://www.bssd.eu/blog/?p=113 macht auch eine interessante Lektüre.

assertEquivalent von https://github.com/KentBeck/junit/pull/228 sollte dies beheben.

Danke dsaff. Diese Arbeit sieht toll aus. Ich habe dies noch nicht getan, bedeutet dies, dass ich die Junit-Quelle abrufen, diese Pull-Anforderung selbst zusammenführen und einen benutzerdefinierten Build erstellen muss?

Aus der Hilfe unter http://help.github.com/send-pull-requests/ scheint ich sollte:

git-Klon https://github.com/KentBeck/junit.git
cd junit

und dann eine Fernbedienung für die Pull-Anforderung hinzufügen, dann entweder holen, zusammenführen oder beides tun.

Ist die Verwendung in einer Anwendung angesichts der Tatsache, dass dies ein Pull-Request zu sein scheint, also kein offizielles Junit, ratsam? Besteht die Möglichkeit, dass dies außerhalb der Hauptabteilung schimmelt und ich Probleme habe, meinen Code an andere zu senden, für die er nicht erstellt wird?

Neekfenwick,

Ja, Sie sind auf dem richtigen Weg, wie Sie es jetzt tun. Ich beabsichtige, diesen Pull in den 4.10-Zweig einzufügen, aber der ursprüngliche Autor hatte Probleme, den Git-Status zusammenzuführen. Wenn Sie Zeit haben, der Welt einen Gefallen zu tun, könnten Sie das KentBeck-Repo abspalten, alles zusammenführen und einen Pull-Request gegen den 4.10-Zweig ausgeben, damit es für alle einfacher ist (wenn es beliebt klingt, könnte ich sogar drehen irgendwann ein 4.10-Vorschauglas).

Ich habe das wirklich noch nie gemacht :) Also habe ich das Repo gegabelt und [email protected] :neekfenwick/junit.git auf meinen lokalen Computer geklont (ich habe bereits ein github-Konto und ssh-Schlüssel eingerichtet) und hinzugefügt eine Fernbedienung für das Repo, aus dem ich es gegabelt habe:

git remote add upstream https://github.com/KentBeck/junit.git

Nur zur Sicherheit habe ich verzweigt, damit ich den Pull-Request an einem anderen Ort als HEAD zusammenführen kann:

git branch merge_pullreq_228
git checkout merge_pullreq_228

Jetzt sagen die Dokumente, die ich finden kann, "jetzt den Pull-Request in Ihren Branch zusammenführen". Ich kann die Commits für Pull 228 unter https://github.com/KentBeck/junit/pull/228/commits sehen, aber ich kann sie nicht zusammenführen:

[neek junit (merge_pullreq_228)]$ git merge 57b49344
fatal: '57b49344' does not point to a commit

Da der Pull-Request nicht für mein eigenes Repo/Branch ist, kann ich die Merge-Tools in der Github-Web-GUI (AFAIK) nicht verwenden.

Liege ich richtig in der Annahme, dass Sie möchten, dass ich die 7 Commits in meinen eigenen Zweig einfüge und ihn dazu bringe, Komponententests zu erstellen/zu bestehen? Könnten Sie buchstabieren, was zu tun ist, um einen dieser Commits zusammenzuführen, um mich auf den Weg zu bringen?

Richtig, Sie können die Web-Merge-Tools nicht verwenden. Was meiner Meinung nach funktionieren sollte, ist:

git remote leet3lite hinzufügen https://github.com/leet3lite/junit.git

Und dann von deiner Filiale aus anrufen

git pull leet3lite master

Leider vergesse ich normalerweise eine Sache, wenn ich beschreibe, wie man git "über das Telefon" verwendet, also lassen Sie mich wissen, ob das für Sie funktioniert.

Ah, ich sehe, ich muss nicht jeden dieser Commits zusammenführen. Der Master-Zweig von leet3lite hat sie bereits, und das Zusammenführen dieser Arbeit in den ursprünglichen Master ist das Problem.

Es scheint Zusammenführungskonflikte zwischen diesem Zweig und HEAD zu geben. Ich denke, das ist der Sinn dieser Übung.

[neek junit (merge_pullreq_228)]$ git remote add leet3lite https://github.com/leet3lite/junit.git
[neek junit (merge_pullreq_228)]$ git pull leet3lite master
remote: Counting objects: 100, done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 85 (delta 34), reused 77 (delta 26)
Unpacking objects: 100% (85/85), done.
From https://github.com/leet3lite/junit
 * branch            master     -> FETCH_HEAD
Auto-merging acknowledgements.txt
CONFLICT (content): Merge conflict in acknowledgements.txt
Auto-merging src/main/java/org/junit/Assert.java
Auto-merging src/test/java/org/junit/tests/AllTests.java
CONFLICT (content): Merge conflict in src/test/java/org/junit/tests/AllTests.java
Automatic merge failed; fix conflicts and then commit the result.
[neek junit (merge_pullreq_228|MERGING)]$ 

Wenn das für Sie vernünftig erscheint, werde ich morgen damit fortfahren. Fast Mitternacht hier.

Das sieht so aus, als wären Sie hier richtig. Acknowledgements.txt und AllTests.java werden oft berührt, normalerweise nur mit Adds, so dass der Zusammenführungsvorgang wahrscheinlich ein einfacher Akt ist, bei dem alle Zeilen eingeschlossen werden, die auf beiden Pfaden hinzugefügt wurden.

Vielen Dank, dass Sie das vorantreiben.

Ich glaube, das wurde vor 2 Jahren behoben.

dsaff --Nein ...?

Nicht in 4.11 ;( Ich brauche diese Funktion auch

Die Diskussion über assertEquivalent() auf #228 verschoben und danach, glaube ich, auf #376, wo wir entschieden haben, dass Hamcrest das Problem wirklich lösen sollte.

@junit-team/junit-committers irgendwelche Einwände dagegen, dass ich das schließe?

Keine Einwände von meiner Seite.

Ups, Freudscher Klick. :-) Keine Einwände hier.

Okay. Schließe dann.

Ich glaube nicht, dass die Verwendung des Hamcrest-Matchers dieses Problem behebt. Zum Beispiel dieser Code:

   assertThat(product.getRating(), is(equalTo(new BigDecimal("2.3"))));

wird dieses Ergebnis ergeben:

Expected: is <2.3>
     but: was <2.30000>

Ich denke, junit oder hamcrest braucht immer noch die Methode isNumericEquivalent .

Haben Sie versucht, comparesEqualTo ?

Ja, comparesEqualTo funktioniert tatsächlich. Vielen Dank.

Hier ist ein Spickzettel, den ich vor einiger Zeit erstellt habe:
http://www.marcphilipp.de/blog/2013/01/02/hamcrest-quick-reference/

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

sbrannen picture sbrannen  ·  22Kommentare

sabi0 picture sabi0  ·  13Kommentare

cardil picture cardil  ·  9Kommentare

kcooney picture kcooney  ·  108Kommentare

diogoeag picture diogoeag  ·  35Kommentare