12

当涉及隐式参数时,我很难理解如何在 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。

我可以通过添加将 marshaller 带入范围,implicit val marshaller: Marshaller[Result] = mock[Marshaller[Result]]但是当我运行测试时,使用了不同的 Marshaller 实例,因此验证失败。

即使明确地将模拟 Marshaller 传递给complete失败。

那么,任何人都可以建议如何为隐式参数创建一个模拟对象并确保使用该实例吗?

4

1 回答 1

5

这是将MatcherMockito 中的 a 用于 marshaller arg 的完美情况。您不需要模拟隐式编组器。您真正想要做的就是验证是否complete调用了result与您期望的匹配以及编组器的某些实例。首先,如果您还没有这样做,请使用如下导入将 Mockito 匹配器带入范围:

import org.mockito.Matchers._

然后,如果您想对结果进行参考匹配,您可以像这样进行验证:

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

或者,如果你想对结果进行等于匹配,你可以这样做:

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

匹配器的诀窍是,一旦你使用一对一的参数,你就必须对所有的参数使用它们,所以这就是为什么我们也必须使用一个result

于 2013-05-12T23:34:49.840 回答