I'm trying to write a unit test for a function that returns a tuple of a class that contains an array.
A simple assert(out === expectedOut)
or out should be(expectedOut)
does not compare the contents of the classes on the LHS and RHS because of the Array. Is there a neat way to do that in ScalaTest?
I've looked at custom matchers but I'm not sure if that's the best way for what I'm trying to do. So any info from experience of the experts would be much appreciated.
Edit: Here is a case where that does not seem to be the case:
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)
}
}
The test fails because the sortWith
causes a new array to be created and is thus pointing to a different memory location, as far as I can tell.
UPDATE: with the code example, this is clearer:
Comparison fails because shoud be
uses the case class's equals
function to perform the comparison, and case classes don't compare arrays "deeply" - which means, as you suspected, that different instances will not be equal (see more info here).
Workarounds:
Verify equality of each "part" of the case class separately:
prod.get.prices should be(expectedProd.get.prices)
prod.get.id should be(expectedProd.get.id)
If using Array
is not a must, you can change the case class to use Seq[Int]
, which would make the test pass, because a Seq
's implementation of equals
is "deep"
Comparing Arrays:
When compared "on their own", arrays are compared as expected ("deeply") by Matchers' should be
:
arr1 should be(arr2) // true if contents is the same
If you just want to compare the contents, without verifying that out
is indeed an Array
, you can use theSameElementsInOrderAs
:
arr1 should contain theSameElementsInOrderAs arr2