I have a case class which is a simple wrapper around a collection:
final case class Foo(foos: Seq[Int])
and in my tests, I'd like to make assertions about the emptiness and lone elements of Foo#foos
. I'm currently circumventing the problem by accessing Foo#foos
directly:
foo.foos shouldBe empty
or
foo.foos.loneElement should===(1)
This works, but breaks encapsulation.
I've looked through the scalatest docs, but haven't found a way to define these operators outside of a companion.
How can I define them? Bonus points for inlining them in the tests.
Define some implicits to deal with Foo
(in the test
-directory, not in the main
source code tree):
import org.scalatest.enablers.Emptiness
trait FooImplicits {
case class FooLoneElementWrapper(wrapped: Foo) {
def loneElement: Int = {
assert(wrapped.foos.size == 1)
wrapped.foos(0)
}
}
implicit def fooCanHazLoneElement(foo: Foo) = FooLoneElementWrapper(foo)
implicit object FooEmptiness extends Emptiness[Foo] {
def isEmpty(foo: Foo) = foo.foos.isEmpty
}
}
Now simply mixin the trait FooImplicits
into the FlatSpec
where you would like to use it:
import org.scalatest._
class FooSpec extends FlatSpec with Matchers with FooImplicits {
"Foo" should "be empty when it's empty" in {
Foo(Seq()) shouldBe empty
}
it should "have loneElements" in {
val x = Foo(Seq(1))
x.loneElement should equal (1)
}
}
Profit:
[info] Foo
[info] - should be empty when it's empty
[info] - should have loneElements
Notice that the FooImplicits
can be defined in the same package
as Foo
in the main
tree, even though it is in a completely different test
-source-code tree. This way, it can access package-visible members of Foo
.