我有一个junit测试断言两个Double对象,其中包含以下内容:
Assert.assertEquals(Double expected, Double result);
这很好,然后我决定将其改为使用原始的double而不是原来的,除非你也提供了一个delta。
所以我想知道在这个assertEquals中使用Double对象或原始类型有什么区别?为什么在没有delta确定的情况下使用对象,但是不推荐使用没有delta的基元? Java是否在后台执行某些已经考虑了默认增量值的内容?
感谢。
答案 0 :(得分:16)
assertEquals(Double expected, Double result);
然而,对象有一个通用:
assertEquals(Object expected, Object result);
这会调用对象的equals
方法,正如您所料,建议不要将其用于比较Double
个对象。
对于双精度数,正如您所观察到的,绝对有必要使用增量进行比较,以避免浮点舍入问题(在其他一些答案中已有解释)。如果您使用带有assertEquals
参数的double
的3参数版本
assertEquals(double expected, double actual, double delta);
你的Double
将被静默地取消装箱到double
,一切都会正常工作(你的测试不会意外失败: - )。
答案 1 :(得分:5)
如果给出完全相同的结果,则很少使用双数学。例如,0.1 * 0.1 != 0.01
。在比较双精度结果时,通常至少需要一些增量。
另一方面,如果你比较盒装的Double
,它假设你想要完全相等。 Java没有考虑默认增量值,但Double.equals
与==
的行为略有不同:特别是its handling of NaNs。
这在测试中很有意义,因为Double.NaN != Double.NaN
,但在测试中,如果您预期会返回NaN
和NaN
,那么这是正确答案。
答案 2 :(得分:1)
更好地写下这样的东西:
assertEquals(23.0, 250.0, 0.0)
0.0 - 它是delta。请阅读您的方法被弃用的原因。
答案 3 :(得分:0)
SOURCE. 断言两个双精度或浮点数等于正三角形。如果不是,则抛出AssertionError。如果期望值是无穷大,则忽略delta值.NaNs被认为是相等的。
答案 4 :(得分:0)
我会说比较双打,原始或对象,没有三角洲就没用了。了解流动点数如何工作是进行数值工作的关键。
对象可能正在使用.equals;除了==之外,原语没有其他选择。
仅仅因为对象版本没有使用delta,这不是一个更好的主意。
答案 5 :(得分:0)
我正在回答有关 JUnit 5 的更新。无论版本如何,assertEquals(Double expected, Double actual)
都会被路由到 assertEquals(Object expected, Object actual)
,因为正如其他人已经解释的那样,Double
是一个隐式的原始包装器扩展 Object
。
但是 assertEquals(double expected, double actual)
(带有两个原语而不是两个原语包装器)在 JUnit 4 上下文中调用了一个不推荐使用的过程。我不知道它是否已经在 JUnit 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: expected: <0.3> but was: <0.30000000000000004> 在 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.00000000000000001 之类的增量。
如果您愿意,您仍然可以使用 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.fail(Assert.java:88) 在 org.junit.Assert.assertEquals(Assert.java:667) 在 org.junit.Assert.assertEquals(Assert.java:656) ...
许多非常聪明的 Java 程序员学习了 SQL 连接等复杂的东西,他们根本不在乎学习浮点数,所以他们只使用了 0.0 的增量。
因此,JUnit 开发人员似乎认为教育人们了解浮点数的弱点不是他们的工作。因此,org.junit.jupiter.api.Assertions.assertEquals(double expected, double actual)
在技术上是新的,并且根本没有被弃用。
绝对清楚,在 JUnit 5 中仍然可以使用浮点数与 delta 进行比较。从 Scala 的角度来看,您可以将其视为 assertEquals(expected: Double, actual: Double, delta: Double = 0.0)
。