这是使用KotlinTest 1.3.5的测试代码。
val expect = 0.1
val actual: Double = getSomeDoubleValue()
actual shouldBe expect
并且在运行代码时打印了此警告。
[警告]在比较双打时考虑使用容差,例如:a shouldBe b plusOrMinus c
在这种情况下,我不想使用plusOrMinus
。
所以,我修改了代码
val expect = 0.1
val actual: Double = getSomeDoubleValue()
actual shouldBe exactly(expect)
现在,没有警告
不过,我想知道shouldBe
和shouldBe exactly
之间的区别。它是什么?
答案 0 :(得分:4)
比较浮点数,尤其是计算出的浮点数,由于某些浮点数可能无法表示,因此它们被转换为二进制的方式总是会出现舍入误差。因此,在测试时,您通常必须为您认为可接受的舍入误差提供值。
在KotlinTest中,这是使用plusOrMinus
说明符指定的。
如果您知道该数字应该是一个给定值(例如,它初始化为0或10或其他),则使用exactly
说明符。据推测,这可以在幕后做一些事情来指定一个非常小的错误值或以其他方式比较双打。
断言双重完全等于另一个双重用途d shouldBe正好(e)
要断言double在某个容差范围内相等,请使用d shouldBe(e plusOrMinus y)
如果您只使用shouldBe
,那么系统只会执行简单的if a == b
类型测试,这会将您的测试暴露给上述舍入错误。
答案 1 :(得分:4)
infix fun Double.shouldBe(other: Double): Unit = ToleranceMatcher(other, 0.0).test(this)
class ToleranceMatcher(val expected: Double, val tolerance: Double) : Matcher<Double> {
override fun test(value: Double) {
if (tolerance == 0.0)
println("[WARN] When comparing doubles consider using tolerance, eg: a shouldBe b plusOrMinus c")
val diff = Math.abs(value - expected)
if (diff > tolerance)
throw AssertionError("$value is not equal to $expected")
}
infix fun plusOrMinus(tolerance: Double): ToleranceMatcher = ToleranceMatcher(expected, tolerance)
}
因此,匹配d shouldBe e
将完全比较双打而没有任何容差(a - b
will never give 0
for different doubles)并打印警告:
[警告]在比较双打时考虑使用容差,例如:a shouldBe b plusOrMinus c
exactly(d)
is defined as
fun exactly(d: Double): Matcher<Double> = object : Matcher<Double> {
override fun test(value: Double) {
if (value != d)
throw AssertionError("$value is not equal to expected value $d")
}
}
所以它会做同样的,但没有任何警告。
我想,这个警告的意思是鼓励开发人员明确指定双精度进行精确比较,或者指定公差,因为即使是以不同顺序完成的相同算术也可能会产生不同的双精度结果。