3

I was wondering why ScalaTest behaves differently compared to Specs2.

Specs2

"" must be equalTo 3
TestSpec.scala:11:26: type mismatch;
[error]  found   : Int(3)
[error]  required: String
[error]       "" must be equalTo 3

ScalaTest

3 should === ("r")
[info] Done compiling.
[info] TestTest:
[info] Dummy test
[info] - should fail *** FAILED ***
[info]   "" did not equal 3 (PersistentTaskRuntimeTest.scala:21)

ScalaTest by default only fails at runtime, everything is compared as Any-to-Any.

There is the Supersafe plugin to get better checks (or TypeCheckedTripleEquals) but these feel like hacks as Specs2 just uses the scala compiler to require the types of the two values compared to be in a subtype/supertype relationship.

For reference this is the output when using TypeCheckedTripleEquals, mind the hacky CanEqual

TestTest.scala:21:7: types String and Int do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[String,Int]
[error]     "" should === (3)
[error]       ^

So what is the rationale behind this?

  • Less heavy for the scala compiler?
  • Less code to write for ScalaTest?
  • Less implicit magic (cryptic error messages)?
  • Pushing a commercial compiler plugin?
z12345
  • 2,186
  • 4
  • 20
  • 28
Somatik
  • 4,723
  • 3
  • 37
  • 49

1 Answers1

1

TypeCheckedTripleEquals is using generalised type constraints, for example, B <:< A in

implicit override def typeCheckedConstraint[A, B](implicit equivalenceOfA: Equivalence[A], ev: B <:< A): A CanEqual B

This is standard Scala functionality to enforce compile-time safety, and is used in many widespread Scala libraries. For example,

import org.scalactic.TypeCheckedTripleEquals
import org.scalatest._

class CompileTimeSafetySpec extends FlatSpec with Matchers with TypeCheckedTripleEquals {
  "TypeCheckedTripleEquals" should "provide compile-time safety" in {
    3 should === ("r")
  }
}

gives compiler error

types Int and String do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Int,String]
[error]     3 should === ("r")
Mario Galic
  • 47,285
  • 6
  • 56
  • 98