我正在尝试为一个返回包含数组的类的元组的函数编写单元测试。
由于数组,简单的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
导致创建一个新数组,因此我指的是不同的内存位置。
答案 0 :(得分:2)
UPDATE :使用代码示例,这一点更加清晰:
比较失败,因为shoud be
使用案例类的equals
函数来执行比较,并且案例类不会“深入”地比较数组 - 这意味着,正如您所怀疑的那样,不同的实例不会是平等的(见更多信息here)。
<强>变通方法强>:
分别验证案例类的每个“部分”的相等性:
prod.get.prices should be(expectedProd.get.prices)
prod.get.id should be(expectedProd.get.id)
如果不必使用Array
,则可以将案例类更改为使用Seq[Int]
,这将使测试通过,因为Seq
的实现equals
“深度”
比较数组:
当比较“自己”时,数组会按照预期(“深度”)由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个值是否属于同一类型,但是由于类型擦除,类型参数没有被检查,所以在某些情况下输入-参数值可能被确定为相等,即使它们的类型不同。