13

我有一个junit测试断言两个Double对象具有以下内容:

Assert.assertEquals(Double expected, Double result);

这很好,然后我决定将其更改为使用原始双精度而不是被弃用,除非您还提供增量。

所以我想知道在这个 assertEquals 中使用 Double 对象或原始类型有什么区别?为什么使用没有 delta 的对象可以,但不推荐使用没有 delta 的原语?Java 是否在后台做一些已经考虑到默认增量值的事情?

谢谢。

4

6 回答 6

19

JUnit 中没有带有签名的断言方法

assertEquals(Double expected, Double result);

然而,有一个通用的对象:

assertEquals(Object expected, Object result);

这会调用对象的equals方法,正如您所料,不建议使用它来比较Double对象。

正如您所观察到的,对于双精度数,绝对有必要使用 delta 进行比较,以避免浮点舍入问题(已在其他一些答案中解释过)。如果您使用assertEqualsdouble参数的 3 参数版本

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

Double的 s 将被默默地拆箱double,一切都会正常工作(并且您的测试不会意外失败:-)。

于 2012-06-28T10:07:30.413 回答
6

双重数学很少给出完全相同的结果。例如,0.1 * 0.1 != 0.01。在比较双精度结果时,通常至少需要一些增量。

另一方面,如果您要比较 boxed Doubles,它假定您想要完全相等。Java 没有考虑默认的 delta 值,但Double.equals与 的行为略有不同==:特别是它对 NaN 的处理

这在测试中是有意义的,因为Double.NaN != Double.NaN,但是在测试中,如果您期望 anNaN并且NaN返回,那是一个正确的答案。

于 2012-06-28T10:06:19.740 回答
6

最好写这样的东西:

assertEquals(23.0, 250.0, 0.0)  

0.0 - 它是增量。阅读为什么不推荐使用您的方法。

于 2017-05-24T12:46:31.773 回答
0

资源。 断言两个双精度或浮点数在正增量内相等。如果不是,则抛出 AssertionError。如果期望值为无穷大,则忽略增量值。NaN 被视为相等。

于 2012-06-28T10:05:16.267 回答
0

我会说比较双打,原始或对象,没有增量是没有用的。了解流动点数的工作原理是进行数值工作的关键。

该对象可能在幕后使用 .equals ;除了==之外,原语别无选择。

仅仅因为对象版本没有使用增量并不能使它成为一个更好的主意。

于 2012-06-28T10:05:48.070 回答
0

我正在回答有关 JUnit 5 的更新。无论版本如何,assertEquals(Double expected, Double actual)都会被路由到assertEquals(Object expected, Object actual),因为正如其他人已经解释的那样,Double它是隐式扩展的原始包装器Object

但是assertEquals(double expected, double actual)(使用两个原语而不是两个原语包装器)在 JUnit 4 上下文中调用已弃用的过程。我不知道它是否已经在 J​​Unit 3 中被弃用。但猜猜看:它在 JUnit 5 中没有被弃用。

像这样的浮点类型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> 但在 org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55) 处为 <0.30000000000000004> 在 org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils .java:62) 在 org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:65) 在 org.junit.jupiter 的 org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:70)。 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) ...

许多非常聪明的 Java 程序员学习了 SQL 连接等复杂的东西,根本不关心浮点数,所以他们只使用 0.0 的 delta。

因此,JUnit 开发人员似乎认为教育人们了解浮点的弱点不是他们的工作。所以org.junit.jupiter.api.Assertions.assertEquals(double expected, double actual)在技术上是新的,根本没有被弃用。

绝对清楚,在 JUnit 5 中仍然可以使用 delta 进行浮点比较。从 Scala 的角度来看,您可以将其视为assertEquals(expected: Double, actual: Double, delta: Double = 0.0).

于 2021-02-28T00:07:10.420 回答