15 Stimmen

Junit Unterschied zwischen assertEquals (Double, Double) und assertEquals (double, double, delta)

Ich hatte einen JUnit-Test, der zwei Double-Objekte mit dem folgenden verglich:

Assert.assertEquals(Double expected, Double result);

Zuerst war das in Ordnung, dann beschloss ich, es stattdessen mit dem primitiven double-Typ zu verwenden, der jedoch veraltet ist, es sei denn, Sie geben auch einen Delta-Wert an.

Also frage ich mich, was der Unterschied zwischen der Verwendung des Double-Objekts oder des primitiven Typs in diesem assertEquals ist. Warum ist die Verwendung der Objekte ohne Delta in Ordnung, aber dann die Verwendung der primitiven Typen ohne Delta veraltet? Macht Java im Hintergrund etwas, das bereits einen Standard-Deltawert berücksichtigt?

Danke.

0voto

Alonso del Arte Punkte 920

Ich antworte auf das Update bezüglich JUnit 5. Unabhängig von der Version wird assertEquals(Double expected, Double actual) auf assertEquals(Object expected, Object actual) umgeleitet, weil, wie andere bereits erklärt haben, Double ein primitiver Wrapper ist, der implizit Object erweitert.

Aber assertEquals(double expected, double actual) (mit zwei Primitiven anstelle von zwei primitiven Wrappern) ruft in einem JUnit 4-Kontext ein veraltetes Verfahren auf. Ich weiß nicht, ob es bereits in JUnit 3 veraltet war. Aber raten Sie mal: In JUnit 5 ist es nicht veraltet.

Gleitkommatypen wie double sind grundsätzlich ungenau. Angenommen, expected = 0.3. Wie wird actual berechnet? Wenn es 3.0 / 10 ist, könnte das Ergebnis genau sein. Aber wenn es das berüchtigte 0.1 + 0.2 ist, wird es um 0,00000000000000004 abweichen (was irgendwie zu 5.551115123125783 × 1017 wird, wenn Sie 0.3 abziehen).

Allgemein gesprochen sind Gleitkomma-Multiplikation und -Division zuverlässiger als Gleitkomma-Addition und -Subtraktion.

Das folgende Beispiel stammt aus einer Testklasse mit einem org.junit.jupiter.api.Assertions.* statischen Import.

    @Test
    void testDeltaBeispiel() {
        double expected = 0.3;
        double actual = 0.1 + 0.2;
        assertEquals(expected, actual);
    }

Ergebnis:

org.opentest4j.AssertionFailedError: erwartet: <0.3> aber war: <0.30000000000000004> at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55) at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62) bei org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:70) bei org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:65) bei org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:868) ...

Stört es Sie, wenn es um einen winzigen Betrag abweicht? Wenn nicht, dann möchten Sie einen Delta von 0.0000000000000001.

Sie können immer noch das "Vintage" JUnit aus JUnit 5 verwenden, wenn Sie möchten (aber Sie sollten es aus keinem anderen Grund wollen, als dass Sie bereits vorhandene Test-Suiten migrieren oder sehen wollen, dass es möglich ist).

    @Test
    void testDeltaBeispiel() {
        double expected = 0.3;
        double actual = 0.1 + 0.2;
        org.junit.Assert.assertEquals(expected, actual);
    }

(Ihr IDE sollte eine Durchstreichung in der Zeile vor der schließenden geschweiften Klammer anzeigen). Dieser Test wird fehlschlagen, auch wenn expected und actual das genau gleiche Bitmuster haben (was sie in diesem Beispiel nicht haben).

java.lang.AssertionError: Verwenden Sie assertEquals(expected, actual, delta) um Gleitkommazahlen zu vergleichen bei org.junit.Assert.fail(Assert.java:88) bei org.junit.Assert.assertEquals(Assert.java:667) bei org.junit.Assert.assertEquals(Assert.java:656) ...

Viele ziemlich intelligente Java-Programmierer, die so komplizierte Dinge wie SQL-Joins gelernt haben, haben sich einfach nicht darum gekümmert, sich mit Gleitkommazahlen zu beschäftigen, und haben einfach einen Delta von 0.0 verwendet.

Und so scheint es, als hätten die JUnit-Entwickler beschlossen, es sei nicht ihre Aufgabe, die Leute über die Tücken von Gleitkommazahlen aufzuklären. Daher ist org.junit.jupiter.api.Assertions.assertEquals(double expected, double actual) technisch neu und überhaupt nicht veraltet.

Um es ganz klar zu sagen, der Vergleich von Gleitkommazahlen mit einem Delta ist immer noch in JUnit 5 verfügbar. Aus Sicht von Scala können Sie es als assertEquals(expected: Double, actual: Double, delta: Double = 0.0) betrachten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X