13

次の2つのDoubleオブジェクトをアサートするjunitテストがありました。

Assert.assertEquals(Double expected, Double result);

これは問題なかったので、代わりにプリミティブdoubleを使用するように変更することにしました。これは、デルタも提供しない限り、非推奨であることが判明しました。

だから私が疑問に思っているのは、このassertEqualsでDoubleオブジェクトとプリミティブ型を使用することの違いは何ですか?デルタなしでオブジェクトを使用しても問題ないのに、デルタなしでプリミティブを使用することが非推奨になるのはなぜですか?Javaは、デフォルトのデルタ値がすでに考慮されているバックグラウンドで何かを実行していますか?

ありがとう。

4

6 に答える 6

19

JUnitには署名付きのassertメソッドはありません

assertEquals(Double expected, Double result);

ただし、オブジェクトに一般的なものが1つあります。

assertEquals(Object expected, Object result);

これはオブジェクトのequalsメソッドを呼び出します。ご想像のとおり、これをオブジェクトの比較に使用することはお勧めしませんDouble

ダブルスの場合、観察したように、浮動小数点の丸めの問題を回避するために、比較のためにデルタを使用することが絶対に必要です(他のいくつかの回答ですでに説明されています)。withargumentsの3引数バージョンを使用するassertEquals場合double

assertEquals(double expected, double actual, double delta);

Doubleは静かに箱から出され、すべてが正常に機能しますdouble(そして、テストが予期せず失敗することはありません:-)。

于 2012-06-28T10:07:30.413 に答える
6

ダブル数学がまったく同じ結果をもたらすことはめったにありません。たとえば、0.1 * 0.1 != 0.01。通常、倍精度の結果を比較するには、少なくともある程度のデルタが必要です。

一方、ボックス化されDoubleたsを比較している場合は、正確な同等性が必要であると想定しています。Javaには、考慮されるデフォルトのデルタ値はありませんが、特にNaNの処理とDouble.equalsは少し異なる動作をします。 ==

これはテストでは理にかなっています。なぜなら、テストでは、とが返さDouble.NaN != Double.NaNれることを期待していた場合、それは正解です。NaNNaN

于 2012-06-28T10:06:19.740 に答える
6

このようなものを書く方が良いです:

assertEquals(23.0, 250.0, 0.0)  

0.0-デルタです。メソッドが非推奨になった理由をお読みください。

于 2017-05-24T12:46:31.773 に答える
0

ソース。 2つのダブルまたはフロートが正のデルタ内に等しいことを表明します。そうでない場合は、AssertionErrorがスローされます。期待値が無限大の場合、デルタ値は無視されます。NaNは等しいと見なされます。

于 2012-06-28T10:05:16.267 に答える
0

プリミティブまたはオブジェクトのdoubleを比較することは、デルタがないと役に立たないと思います。流動点数がどのように機能するかを知ることは、数値作業を行うための鍵です。

オブジェクトは、内部で.equalsを使用している可能性があります。プリミティブには==以外のオプションはありません。

オブジェクトバージョンがデルタを使用していないという理由だけで、それはより良い考えにはなりません。

于 2012-06-28T10:05:48.070 に答える
0

私はJUnit5に関する更新に答えています。バージョンに関係なく、assertEquals(Double expected, Double actual)にルーティングされますassertEquals(Object expected, Object actual)。これは、他の人がすでに説明したように、Double暗黙的に拡張するプリミティブラッパーであるためObjectです。

ただし、assertEquals(double expected, double actual)(2つのプリミティブラッパーではなく2つのプリミティブを使用して)JUnit 4コンテキストでは、非推奨のプロシージャが呼び出されます。JUnit 3ですでに非推奨になっているのかどうかはわかりませんが、JUnit5では非推奨ではありません。

のような浮動小数点タイプdoubleは本質的に不正確です。と仮定しexpected = 0.3ます。どのようにactual計算されますか?その場合3.0 / 10、結果は正確である可能性があります。しかし、それが悪名高い場合0.1 + 0.2は、0.00000000000000004だけオフになります(0.3を引くと、どういうわけか5.551115123125783×10 -17になります)。

一般的に、浮動小数点の乗算と除算は、浮動小数点の加算と減算よりも信頼性があります。

次の例は、org.junit.jupiter.api.Assertions.*静的インポートを使用したテストクラスからのものです。

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

結果:

org.opentest4j.AssertionFailedError:予期された:<0.3>が、だった:<0.30000000000000004> at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils .java:62)org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:70)at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:65)atorg.junit.jupiter。 api.Assertions.assertEquals(Assertions.java:868)..。

そのように少しずれていても気になりますか?そうでない場合は、0.0000000000000001のようなデルタが必要になります。

必要に応じて、JUnit 5の「ビンテージ」JUnitを引き続き使用できます(ただし、既存のテストスイートを移行する場合、または移行できることを確認する場合以外の理由で使用することはできません)。

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

(IDEは、閉じ中括弧の前の行に取り消し線を表示する必要があります)。このテストは、ビットパターンがまったく同じexpectedであっても失敗します(この例では失敗します)。actual

java.lang.AssertionError:assertEquals(expected、actual、delta)を使用して、org.junit.Assert.assertEquals(Assert.java:667)のorg.junit.Assert.fail(Assert.java:88)の浮動小数点数を比較します。 )org.junit.Assert.assertEquals(Assert.java:656)で..。

SQL結合などの複雑なことを学んだ非常にインテリジェントなJavaプログラマーの多くは、浮動小数点数について学ぶことを気にしないため、0.0のデルタを使用しました。

そのため、JUnit開発者は、浮動小数点の可能性について人々を教育するのは彼らの仕事ではないと判断したようです。したがってorg.junit.jupiter.api.Assertions.assertEquals(double expected, double actual)、技術的には新しく、非推奨ではありません。

完全に明確にするために、デルタとの浮動小数点の比較は、JUnit 5でも引き続き使用できます。Scalaの観点からは、これをと見なすことができますassertEquals(expected: Double, actual: Double, delta: Double = 0.0)

于 2021-02-28T00:07:10.420 に答える