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