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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With