Dao De Code

Scalatest and type-safe equality

In Scalatest when using matchers you have many ways to test for equality, but only one of those is type-safe - should ===()
So, if you have a function returning Int, like

  def f(i: Int): Int = i

then the only type-safe way to test it is to use should ===() syntax, like

f(5) should ===(5)  

The other matchers will also work

f(5) should be(5)  
f(5) shouldBe 5  
f(5) should equal(5)  
f(5) shouldEqual 5  

but if you change return type of your function (let's say to String - def f(i:Int): String = i.toString), then they will continue to compile, but fail at runtime.
Not a big deal one might say, and that's true. Sort of. I would prefer my code not even compile so that I know about the issue ASAP. That's one of the reasons we have type systems.

So should ===(5) is the way to go. But to my personal taste it's somewhat less readable than for example shouldBe .
First thing I don't like about it is the mix - one word (should) and one symbolic operator(===). The second sub-optimal thing is mandatory () around right side. As I mentioned above, shouldBe solves both of those issues, but is not type-safe.

We do have a base class for all our tests (as suggested by scalatest guide), so we added the following code to get easy-to-read and type-safe way of equality check

class MyBaseSpec extends WordSpec with Matchers {  
  implicit class ShouldEqOps[A: Equality](left: A) {
    def shouldEq(right: A) = left shouldEqual right
  }
}

And now most of our equality checks are type-safe and read nicely

f(5) shouldEq 5  
comments powered by Disqus