我有一个关于junit assertEquals
来测试双值的问题。阅读API文档,我可以看到:
@Deprecated public static void assertEquals(double expected, double actual)
已过时。使用assertEquals(double 预期,双重实际,双倍 epsilon)而不是
epsilon
值是什么意思? (Epsilon是希腊字母表中的一封信,对吧?)。
有人可以向我解释如何使用它吗?
答案 0 :(得分:186)
Epsilon是2个数字可以关闭的值。因此,只要Math.abs(expected - actual) < epsilon
答案 1 :(得分:111)
这是哪个版本的JUnit?我只见过delta,而不是epsilon - 但这是一个副作用!
来自JUnit javadoc:
delta - 两者之间的预期和实际之间的最大增量 数字仍然被认为是平等的。
这可能有些过分,但我通常会使用一个非常小的数字,例如
private static final double DELTA = 1e-15;
@Test
public void testDelta(){
assertEquals(123.456, 123.456, DELTA);
}
如果您正在使用hamcrest断言,则可以使用带有两个双精度的标准equalTo()
(它不使用delta)。但是,如果您想要增量,则只需使用closeTo()
(请参阅javadoc),例如
private static final double DELTA = 1e-15;
@Test
public void testDelta(){
assertThat(123.456, equalTo(123.456));
assertThat(123.456, closeTo(123.456, DELTA));
}
仅使用两个双打调用assertEquals()
时,即将到来的JUnit 5也将make delta optional。 implementation(如果您感兴趣的话)是:
private static boolean doublesAreEqual(double value1, double value2) {
return Double.doubleToLongBits(value1) == Double.doubleToLongBits(value2);
}
答案 2 :(得分:55)
浮点计算并不精确 - 通常存在舍入错误和由于表示而导致的错误。 (例如,0.1不能用二进制浮点精确表示。)
因此,直接比较两个浮点值是否相等通常不是一个好主意,因为它们可能会有少量不同,具体取决于它们的计算方式。
在JUnit javadocs中调用的“delta”描述了你可以容忍它们仍然被认为是相等的值的差异量。此值的大小完全取决于您要比较的值。比较双打时,我通常使用预期值除以10 ^ 6。
答案 3 :(得分:11)
由于浮点数固有的精度问题,两个double可能不完全相等。使用此delta值,您可以根据错误因素控制相等性评估。
此外,某些浮点值可能具有特殊值,如NAN和-Infinity / + Infinity,它们会影响结果。
如果你真的打算比较两个双打完全相同,最好将它们作为一个长表示进行比较
Assert.assertEquals(Double.doubleToLongBits(expected), Double.doubleToLongBits(result));
或者
Assert.assertEquals(0, Double.compareTo(expected, result));
可以考虑这些细微差别。
我没有深入研究过有问题的Assert方法,但我只能假设之前的这类问题已被弃用,而新版本确实考虑了这些问题。
答案 4 :(得分:2)
请注意,如果您没有进行数学运算,那么断言确切的浮点值并没有错。例如:
public interface Foo {
double getDefaultValue();
}
public class FooImpl implements Foo {
public double getDefaultValue() { return Double.MIN_VALUE; }
}
在这种情况下,您需要确保它真的是MIN_VALUE
,而不是零或-MIN_VALUE
或MIN_NORMAL
或其他一些非常小的值。你可以说
double defaultValue = new FooImpl().getDefaultValue();
assertEquals(Double.MIN_VALUE, defaultValue);
但是这会给你一个弃用警告。为避免这种情况,您可以改为呼叫assertEquals(Object, Object)
:
// really you just need one cast because of autoboxing, but let's be clear
assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);
而且,如果你真的想要看起来很聪明:
assertEquals(
Double.doubleToLongBits(Double.MIN_VALUE),
Double.doubleToLongBits(defaultValue)
);
或者你可以使用Hamcrest流畅的断言:
// equivalent to assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);
assertThat(defaultValue, is(Double.MIN_VALUE));
如果您正在检查的值来自做一些数学运算,请使用epsilon。
答案 5 :(得分:1)
Epsilon是expected
和actual
值之间的差异,您可以接受它们认为它们是平等的。例如,您可以设置.1
。
答案 6 :(得分:0)
我只想提到很棒的AssertJ库。这是我去JUnit 4和5的断言库的方法,并且还优雅地解决了这个问题:
assertThat(actual).isCloseTo(expectedDouble, within(delta))
答案 7 :(得分:-2)
Assert.assertTrue(Math.abs(actual-expected) == 0)