Java assertEquals(双精度,双精度)和assertEquals(双精度,双精度,增量)之间的Junit差异

Java assertEquals(双精度,双精度)和assertEquals(双精度,双精度,增量)之间的Junit差异,java,unit-testing,junit,Java,Unit Testing,Junit,我有一个junit测试,断言两个具有以下内容的双对象: Assert.assertEquals(Double expected, Double result); 这很好,然后我决定将它改为使用原语double,结果发现它已被弃用,除非您还提供了delta 所以我想知道的是,在这个assertEquals中使用双对象或原语类型有什么区别?为什么使用不带增量的对象可以,但使用不带增量的基本体则不推荐?Java是否正在后台做一些已经考虑了默认增量值的事情 谢谢。 断言两个double或float在正

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

Assert.assertEquals(Double expected, Double result);
这很好,然后我决定将它改为使用原语double,结果发现它已被弃用,除非您还提供了delta

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

谢谢。


断言两个double或float在正增量内等于。如果不是,则抛出断言错误。如果期望值为无穷大,则忽略delta值。n被认为是相等的。

我认为,如果没有delta,比较double、primitive或object是无用的。了解流动点数是做数值计算的关键

该对象可能正在使用.equals;原语除了==之外没有其他选项


仅仅因为对象版本没有使用delta并不意味着这是一个更好的主意。

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

另一方面,如果您比较装箱的
Double
s,则它假定您想要完全相等。Java没有考虑默认的增量值,但是
Double.equals
的行为与
=
稍有不同:特别是

这在测试中是有意义的,因为
Double.NaN!=Double.NaN
,但在测试中,如果您预期会出现
NaN
,并且
NaN
被返回,则这是正确答案。

没有签名

assertEquals(Double expected, Double result);
但是,对于对象,有一种是通用的:

assertEquals(Object expected, Object result);
这将调用对象的“
equals
方法,正如您所期望的,不建议将其用于比较
Double
对象

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

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

您的
Double
s将以静默方式解除绑定到
Double
,一切都会正常工作(并且您的测试不会意外失败:-)。

最好编写如下内容:

assertEquals(23.0, 250.0, 0.0)  

0.0-它是增量。阅读为什么您的方法被弃用。

我正在回答有关JUnit5的更新。无论版本如何,
assertEquals(双预期,双实际)
都会被路由到
assertEquals(对象预期,对象实际)
,因为正如其他人已经解释的那样,
Double
是一个隐式扩展
对象的原始包装器

但是JUnit4上下文中的assertEquals(双预期,双实际)
(使用两个原语而不是两个原语包装器)调用了一个不推荐使用的过程。我不知道它在JUnit3中是否已经被弃用了。但是你猜怎么着:它在JUnit5中没有被弃用

double
这样的浮点类型本质上是不精确的。假设
expected=0.3
。如何计算实际值?如果是
3.0/10
,结果可能是准确的。但是如果它是臭名昭著的
0.1+0.2
,它将被关闭0.00000000000000004(不知何故变成了5.551115123125783×10)−17减去0.3)

一般来说,浮点乘法和除法比浮点加减法更可靠

下面的示例来自一个带有
org.junit.jupiter.api.Assertions.*
静态导入的测试类

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

org.opentest4j.AssertionFailedError:应为:但为: 在 org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)位于 org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62) 在 org.junit.jupiter.api.AssertEquals.AssertEquals(AssertEquals.java:70) 在 org.junit.jupiter.api.AssertEquals.AssertEquals(AssertEquals.java:65) 位于org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:868)

你在乎它会不会掉那么一点点吗?如果没有,则需要0.0000000000000001这样的增量

如果愿意的话,您仍然可以使用JUnit5中的“vintage”JUnit(但是您不应该因为迁移现有测试套件或者为了确保它可以完成之外的任何原因而这样做)

(您的IDE应该在右大括号之前的行中显示一个直划线)。即使
预期的
实际的
具有完全相同的位模式(在本例中它们不会),该测试也会失败

assertEquals(预期、实际、增量)用于 在以下位置比较浮点数: org.junit.Assert.fail(Assert.java:88)位于 Assert.assertEquals(Assert.java:667)位于 Assert.Assert.assertEquals(Assert.java:656)

许多相当聪明的Java程序员学习过SQL连接等复杂的知识,他们根本不关心浮点数的学习,所以他们只使用了0.0的增量

因此,JUnit开发人员似乎认为教育人们浮点运算的缺点不是他们的工作。因此,
org.junit.jupiter.api.Assertions.assertEquals(双预期,双实际)
在技术上是新的,完全不受欢迎


非常清楚的是,在JUnit5中,浮点与增量的比较仍然可用。从Scala的角度来看,您可以将其视为
assertEquals(预期值:Double,实际值:Double,delta:Double=0.0)

+1重新拆箱,是的,但需要注意的是,如果一个或另一个Double
    @Test
    void testDeltaExample() {
        double expected = 0.3;
        double actual = 0.1 + 0.2;
        org.junit.Assert.assertEquals(expected, actual);
    }