ScalaTest深度比较最佳实践

时间:2016-04-06 11:24:26

标签: scala scalatest

我正在尝试为一个返回包含数组的类的元组的函数编写单元测试。

由于数组,简单的assert(out === expectedOut)out should be(expectedOut)不会比较LHS和RHS上的类的内容。在ScalaTest中有一种巧妙的方法吗?

我看过自定义匹配器,但我不确定这是否是我尝试做的最佳方式。因此,非常感谢来自专家经验的任何信息。

编辑: 这种情况似乎并非如此:

object Utils {
  case class Product(id: Int, prices: Array[Int])


  def getProductInfo(id: Int, prices: Array[Int]): Option[Product] = {
    val sortedPrices = prices.sortWith(_ < _)
    Some(Product(id, sortedPrices))
  }
}

---

import org.scalatest._
import Utils._

class DataProcessorSpec extends FlatSpec with Matchers with OptionValues {
  val id = 12345
  val priceList = Array(10,20,30)

  val prod = Utils.getProductInfo(id, priceList)
  val expectedProd = Some(Utils.Product(id, priceList))

  "A DataProcessorSpec" should "return the correct product information" in {
     prod should be(expectedProd)
  }
}

测试失败,因为sortWith导致创建一个新数组,因此我指的是不同的内存位置。

2 个答案:

答案 0 :(得分:2)

UPDATE :使用代码示例,这一点更加清晰:

比较失败,因为shoud be使用案例类的equals函数来执行比较,并且案例类不会“深入”地比较数组 - 这意味着,正如您所怀疑的那样,不同的实例不会是平等的(见更多信息here)。

<强>变通方法

  1. 分别验证案例类的每个“部分”的相等性:

    prod.get.prices should be(expectedProd.get.prices)
    prod.get.id should be(expectedProd.get.id)
    
  2. 如果不必使用Array,则可以将案例类更改为使用Seq[Int],这将使测试通过,因为Seq的实现equals “深度”

  3. 比较数组

    当比较“自己”时,数组会按照预期(“深度”)由Matchers'should be进行比较:

    arr1 should be(arr2) // true if contents is the same
    

    如果您只想比较内容,而不验证out确实是Array,则可以使用theSameElementsInOrderAs

    arr1 should contain theSameElementsInOrderAs arr2
    

答案 1 :(得分:0)

正如 Tzach Zohar 在他的回答中所说,should be 使用不“深入”比较数组的 case 类的 equals。

您可以创建一个函数来深入比较任何 2 个案例类(以及任何其他 Product 合法继承者):

def deepEquals(x: Product, y: Product): Unit = {
  if (x.getClass == y.getClass) {
    x.productIterator.zip(y.productIterator)
      .foreach {
        case (xElem: Product, yElem: Product) => deepEquals(xElem, yElem)
        case (xElem, yElem) => xElem should be(yElem)
      }
  } else {
    x should be(y) // Will fail, with an appropriate error
  }
}

注意事项:该函数使用.getClass来检查2个值是否属于同一类型,但是由于类型擦除,类型参数没有被检查,所以在某些情况下输入-参数值可能被确定为相等,即使它们的类型不同。