ScalaTest 如何检查相等性?

How does ScalaTest check equality?

我参考了this.

我是 ScalaTest 的新手,但我将其解释为如果我实现了 ==,那么它将用于解释 should equal。但是,我的代码似乎与此矛盾。

我正在完成 Odersky's book - 我正在进行练习 6.0.3。我已经实现了上面的自然数,并添加了相等运算符:

class Succ(x: Nat) extends Nat {
  ...
  override def ==(that:Nat): Boolean = {
    try {
      (that - this).isZero
    } catch {
      case _: Throwable => false
    }
  }
}

object Zero extends Nat {
  ...
  override def ==(that:Nat): Boolean = {
    that.isZero
  }
}

然而,下面的测试用例失败了:

def makeNat(n:Integer):Nat = {
  if (n < 0) throw new RuntimeException("Can't generate Nat from <0: " + n.toString())
  if (n==0) return Zero
  else return makeNat(n-1).suc
}

test("Addition is commutative") {

   val nats = for (n <- Gen.choose(0, 1000)) yield  makeNat(n)
   val p = forAll ((nats, "n1"), (nats, "n2")) {
      (n1: Nat, n2: Nat) =>
        (n1 + n2) should equal (n2 + n1) //Fails
    }

}

但是减去参数并与零比较通过:

test("Addition is commutative") {

  val nats = for (n <- Gen.choose(0, 1000)) yield  makeNat(n)

  val p = forAll ((nats, "n1"), (nats, "n2")) {
    (n1: Nat, n2: Nat) =>
      ((n1 + n2)-(n2+n1)) should equal (Zero) // Passes
  }

}

编辑:感谢 dwickern@,这已解决 - 我需要为 equals 方法添加覆盖,而不是 == 方法。即:

  override def equals(that:Any): Boolean = that match {
    case that:Nat => (that-this).isZero
    case _ => false
  }

如您所见,您需要覆盖 equals 而不是 ==。 scala 中的 == 方法调用 Java 的标准 Object.equals 除了它正确处理 null 而不会抛出异常。

实际上,您不需要经常重写 equals,因为存在 class 的情况。要使用它们,请将 class 更改为 case class,将 object 更改为 case object。编译器将为您实现 equalshashCode。如果 class 遵循以下模式,则 classes 非常适合:

  • class 被视为一个值。 (对于自然数绝对正确class!)
  • 大小写 class 应该是不可变的。平等和可变性不能混为一谈。
  • 避免class继承。平等+继承很复杂。请改用特征。