Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ScalaTest deep comparison best practices

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.

like image 661
Ian Avatar asked Apr 06 '16 11:04

Ian


People also ask

Should matchers vs must matchers?

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.

What is ScalaTest used for?

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.

What is FlatSpec in Scala?

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.


1 Answers

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:

  1. 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)
    
  2. 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
like image 135
Tzach Zohar Avatar answered Nov 15 '22 05:11

Tzach Zohar