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.
Matchers , but uses the verb must instead of should . The two traits differ only in the English semantics of the verb: should is informal, making the code feel like conversation between the writer and the reader; must is more formal, making the code feel more like a written specification.
ScalaTest permits the usage of any Java mocking framework, or we can use ScalaMock which is a native Scala mocking library. Here, we'll take a quick look at how to use ScalaMock from ScalaTest. In this very simple example, we see how to create a mock object and set an expectation.
Trait FlatSpec is so named because your specification text and tests line up flat against the left-side indentation level, with no nesting needed. FlatSpec 's no-nesting approach contrasts with traits FunSpec and WordSpec , which use nesting to reduce duplication of specification text.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With