Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala testing mocking implicit parameters?

I'm having a bit of a tough time trying to understand how to write tests in Scala when implicit parameters are involved.

I have the following (short version) of my code and test:

Implementation (Scala 2.10, Spray and Akka):

import spray.httpx.SprayJsonSupport._
import com.acme.ResultJsonFormat._

case class PerRequestIndexingActor(ctx: RequestContext) extends Actor with ActorLogging {
  def receive = LoggingReceive {
    case AddToIndexRequestCompleted(result) =>
      ctx.complete(result)
      context.stop(self)
  }
}


object ResultJsonFormat extends DefaultJsonProtocol {
  implicit val resultFormat = jsonFormat2(Result)
}

case class Result(code: Int, message: String)

Test (Using ScalaTest and Mockito):

"Per Request Indexing Actor" should {
    "send the HTTP Response when AddToIndexRequestCompleted message is received" in {
      val request = mock[RequestContext]
      val result = mock[Result]

      val perRequestIndexingActor = TestActorRef(Props(new PerRequestIndexingActor(request)))
      perRequestIndexingActor ! AddToIndexRequestCompleted(result)

      verify(request).complete(result)
    }
  }

This line, verify(request).complete(result) uses an implicit Marshaller to turn Result into JSON.

I can bring a marshaller in to scope by adding implicit val marshaller: Marshaller[Result] = mock[Marshaller[Result]] but when I run the test a different instance of Marshaller is used, so the verification fails.

Even explicitly passing the mock Marshaller to complete fails.

So, can any one advise how to create a mock object for an implicit parameter and make sure that instance is the one used?

like image 555
C0deAttack Avatar asked May 12 '13 12:05

C0deAttack


1 Answers

This is a perfect situation to use a Matcher from Mockito for the marshaller arg. You should not need to mock out the implicit marshaller. All you really want to do is verify that complete was called with a result matching what you expected and also some instance of the marshaller. First, if you haven't already done it, bring the Mockito matchers into scope with an import like so:

import org.mockito.Matchers._

Then, if you wanted reference matching on the result, you could verify like so:

verify(request).complete(same(result))(any[classOf[Marshaller[Result]]])

Or, if you wanted equals matching on result you could do:

verify(request).complete(eq(result))(any(classOf[Marshaller[Result]]))

The trick with matchers is that once you use one for one arg, you have to use them for all args, so that's why we have to use one for result too.

like image 105
cmbaxter Avatar answered Sep 19 '22 14:09

cmbaxter