Search code examples
scalascalatestmatchercase-class

Ignore case class field in ScalaTest matching


Assume I have case class with several field members:

case class User(name: String, ..., createdAt: LocalDateTime)

How could I check equality without taking into account createdAt field?

Is there a better way than:

val expected = User("username", stubDate)
actual shouldBe expected.copy(createdAt = actual.createdAt)

Solution

  • Consider matchPattern like so

    import org.scalatest.flatspec.AnyFlatSpec
    import org.scalatest.matchers.should.Matchers
    
    class CaseClassPatternMatchSpec extends AnyFlatSpec with Matchers {
      case class User(name: String, age: Int)
    
      "User" should "be Worf where we ignore the age" in {
        val actual = User("Worf", 30)
        actual should matchPattern { case User("Worf", _) => }
      }
    }
    

    or define custom equality

    import org.scalactic.Equality
    import org.scalatest.flatspec.AnyFlatSpec
    import org.scalatest.matchers.should.Matchers
    
    class CaseClassPatternMatchSpec extends AnyFlatSpec with Matchers {
      case class User(name: String, age: Int)
      object User {
        implicit val aEq: Equality[User] = (a: User, b: Any) => b match {
          case User(name, _) => a.name == name
          case _ => false
        }
      }
    
      "User" should "be Worf where we ignore the age " in {
        val actual = User("Worf", 30)
        val expected = User("Worf", -11)
        actual should === (expected)
      }
    }
    

    Note only certain matchers can use custom equality

    result should equal (3) // can customize equality
    result should === (3)   // can customize equality and enforce type constraints
    result shouldEqual 3    // can customize equality, no parentheses required