Question

I have a wide array of Hamcrest matchers for my domain objects written in Java. I'm now moving to Scala and would like to reuse these existing matchers in the context of specs2 tests.

Given a Hamcrest matcher for class Foo:

public class FooMatcher extends TypeSafeMatcher[Foo] {
...
}

I'd like to be able to use it thus:

val myFooMatcher = new FooMatcher(...)
foo must match (myFooMatcher)
foos must contain (myFooMatcher1, myFooMatcher2)

And so on.

Specs2 seems to have the opposite, an adapter of its Matcher[T] trait to org.hamcrest.Matcher, but I'm looking for the other way around.

Any ideas?

Was it helpful?

Solution

You need to add one implicit conversion for this to work:

import org.hamcrest._
import org.specs2.matcher.MustMatchers._

implicit def asSpecs2Matcher[T](hamcrest: org.hamcrest.TypeSafeMatcher[T]):     
  org.specs2.matcher.Matcher[T] = {

  def koMessage(a: Any) = {
    val description = new StringDescription
    description.appendValue(a)
    hamcrest.describeTo(description)
    description.toString 
  }
  (t: T) => (hamcrest.matches(t), koMessage(t))  
}

Let's see it in action:

case class Foo(isOk: Boolean = true)

// a Hamcrest matcher for Foo elements
class FooMatcher extends TypeSafeMatcher[Foo] {
  def matchesSafely(item: Foo): Boolean    = item.isOk
  def describeTo(description: Description) = description.appendText(" is ko")
}

// an instance of that matcher
def beMatchingFoo = new FooMatcher

// this returns a success
Foo() must beMatchingFoo

// this returns a failure
Foo(isOk = false) must beMatchingFoo

// this is a way to test that some elements in a collection have
// the desired property
Seq(Foo()) must have oneElementLike { case i => i must beMatchingFoo }

// if you have several matchers you want to try out
Seq(Foo()) must have oneElementLike { case i => 
  i must beMatchingFoo and beMatchingBar 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top