6

这是使用 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。它是什么?

4

2 回答 2

6

根据目前的消息来源

infix fun Double.shouldBe(other: Double): Unit = ToleranceMatcher(other, 0.0).test(this)

ToleranceMatcher在哪里

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永远不会给出0不同的双打)并打印警告:

[警告] 比较双打时考虑使用容差,例如:a shouldBe b plusOrMinus c

exactly(d) 定义为

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")
    }
}

这样它就会做同样的事情,尽管没有任何警告。


我想,这个警告的意思是鼓励开发人员明确指定双精度数是精确比较的,或者指定容差,因为即使以不同的顺序完成相同的算术也可能会产生不同的双精度数结果。

于 2016-11-15T13:53:07.587 回答
4

比较浮点数,尤其是计算的浮点数,总是会出现舍入误差,因为某些浮点数可能无法表示,因为它们被转换为二进制的方式。因此,在测试时,您通常必须为您认为可接受的舍入误差给出一个值。

在 KotlinTest 中,这是使用说明plusOrMinus符指定的。

如果在某些情况下您知道该数字应该是一个给定的值(例如,它被初始化为 0 或 10 或其他),那么请使用说明exactly符。大概这在幕后做了一些事情来指定一个非常小的错误值或以其他方式比较双精度数。

要断言一个双精度数与另一个双精度数完全相等,请使用 d shouldBe exact(e)
要断言双精度数在某个容差范围内相等,请使用 d shouldBe (e plusOrMinus y)

资源

如果你只是单独使用shouldBe它,那么系统只会做一个简单的if a == b类型测试,这会让你的测试暴露在上面提到的舍入错误中。

于 2016-11-15T13:51:18.323 回答