当涉及隐式参数时,我很难理解如何在Scala中编写测试。

我有以下(简短版本)的代码和测试:

实现(Scala 2.10,Spray和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)

测试(使用ScalaTest和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)
    }
  }

这行verify(request).complete(result)使用隐式Marshaller将Result转换为JSON。

我可以通过添加implicit val marshaller: Marshaller[Result] = mock[Marshaller[Result]]将编码器引入范围,但是当我运行测试时,使用了另一个编码器实例,因此验证失败。

甚至将模拟Marshaller明确传递给complete也会失败。

因此,有人可以建议如何为隐式参数创建模拟对象,并确保使用该实例吗?

最佳答案

这是将Mockito中的Matcher用于编码器arg的理想情况。您不需要模拟掉隐式编码器。您真正想要做的就是验证complete被调用的result与您所期望的匹配,并且与marshaller的某些实例匹配。首先,如果您尚未完成此操作,则通过如下所示的导入将Mockito匹配器纳入范围:

import org.mockito.Matchers._

然后,如果要对结果进行引用匹配,则可以像这样进行验证:
verify(request).complete(same(result))(any[classOf[Marshaller[Result]]])

或者,如果您希望结果等于匹配,则可以执行以下操作:
verify(request).complete(eq(result))(any(classOf[Marshaller[Result]]))

匹配器的窍门是,一旦对一个arg使用一个,就必须对所有arg使用它们,因此这就是为什么我们也必须对result使用一个。

10-07 17:29