michele
michele

Reputation: 26598

Scala test match case classes on some field

I have

case class Foo(field1: String, field2: String, field3: String)

expected: Seq[Foo] = Seq(...)

result: Seq[Foo] = Seq(...)

I want to write a Scala matcher that compare the elements of Seq without taking in consideration field1.

So two elements will match if field2 and field3 are equals. Field1 value is not considerated.

Example:

val expected = Seq(
  Foo(
    "f1", "f2", "f3"
  )
)

val result = Seq(
  Foo(
    "fx", "f2", "f3"
  )
)

This two sequence has to match.

  result should matchWithoutId(expected)

Upvotes: 0

Views: 1957

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170815

The documentation is in Using custom Matchers, this example would be (for example)

def matchWithoutId(expected: Foo): Matcher[Foo] = Matcher { actual =>
  MatchResult(
    actual.field2 == expected.field2 && actual.field3 == expected.field3,
    if (actual.field2 != expected.field2)
      s"field2 of $actual was not equal to that of $expected"
    else
      s"field3 of $actual was not equal to that of $expected",
    s"field2 and field3 of $actual were equal to those of $expected")
}

Adjust error messages to taste.

Or another approach (probably a better one in this case):

def matchWithoutId(expected: Foo): Matcher[Foo] = have(
  'field2 (expected.field2),
  'field3 (expected.field3)
)

Normally I'd say using Symbols to name properties and use reflection should be avoided, but here a change to Foo will make the tests fail to compile anyway because of access to expected's fields.

EDIT: I missed that you want to compare Seq[Foo]s and not Foos, so Mario Galic's answer is probably the one you want. Still, this can hopefully be useful as well.

Upvotes: 3

Mario Galic
Mario Galic

Reputation: 48420

Working with "sequences" states

if you want to change how containership is determined for an element type E, place an implicit Equality[E] in scope or use the explicitly DSL.

so the following should work

(expected should contain theSameElementsAs (result)) (decided by fooEqualityWithoutId)

Note about contains usage

Note that when you use the explicitly DSL with contain you need to wrap the entire contain expression in parentheses

Here is the full example

import org.scalactic._
import org.scalatest._
import org.scalatest.matchers.should.Matchers
import org.scalactic.Explicitly._

class CustomizeEqualitySeqSpec extends FlatSpec with Matchers with Explicitly {
  case class Foo(field1: String, field2: String, field3: String)
  val expected = Seq(Foo("f1", "f2", "f3"))
  val result = Seq(Foo("fx", "f2", "f3"))

  val fooEqualityWithoutId = new Equality[Foo] {
    override def areEqual(a: Foo, b: Any): Boolean = b match {
      case Foo(_, field2, field3) => a.field2 == field2 && a.field3 == field3;
      case _ => false
    }
  }

  "Sequences" should "use custom Equality[E]" in {
    (expected should contain theSameElementsAs (result)) (decided by fooEqualityWithoutId)
  }
}

Upvotes: 2

Related Questions