我有一个服务方法如下:
override def update(group: JourneyGroup, name: String, operator: User): Future[Either[String, JourneyGroup]] = {
for {
updatedCount <- journeyGroupDao.update(group.copy(name = name), operator.id.get)
updatedGroup <- journeyGroupDao.findOneById(group.id.get)
} yield
(updatedCount, updatedGroup) match {
case (1, Some(g)) =>
system.eventStream.publish(JourneyGroupUpdated(g, group))
Right(g)
case (1, None) => Left(s"failed to find updated journey group object - ${group.id.get}")
case _ => Left(s"failed to update journey group object - ${group.id.get}")
}
}
它的单元测试看起来像这样:
val existingGroup = mock[JourneyGroup]
existingGroup.id returns Some(123)
val updatedGroup = mock[JourneyGroup]
val operator = mock[User]
operator.id returns Some(876)
doReturn(Future.successful(1)).when(journeyGroupDao).update(Matchers.any[JourneyGroup], Matchers.eq(876))
doReturn(Future.successful(updatedGroup)).when(journeyGroupDao).findOneById(123, includeDeleted = false)
doNothing.when(eventStream).publish(Matchers.any[JourneyGroupUpdated])
val future = journeyGroupService.update(existingGroup, "new name", operator)
Await.result(future, Duration.Inf) must beRight{ g: JourneyGroup =>
g must_=== updatedGroup
}
there was one(eventStream).publish(Matchers.any[JourneyGroupUpdated])
该方法在常规执行中工作得非常好。但是,当我运行测试时,我得到了转换错误:
[error] java.lang.ClassCastException: model.JourneyGroup$$EnhancerByMockitoWithCGLIB$$a9b16db0 cannot be cast to scala.Option (JourneyGroupService.scala:101)
[error] services.JourneyGroupServiceImpl$$anonfun$update$1$$anonfun$apply$1.apply(JourneyGroupService.scala:101)
我甚至不知道从哪里开始。
在for-comprehension的代码中表示:
的返回类型updatedGroup <- journeyGroupDao.findOneById(group.id.get)
为Option[JourneyGroup]
,但在模拟交互的声明中,给出了JourneyGroup
:
val updatedGroup = mock[JourneyGroup]
...
doReturn(Future.successful(updatedGroup)).when(journeyGroupDao).findOneById(123, includeDeleted = false)
updatedGroup
必须为Option[JourneyGroup]
类型
也就是说,我不建议在Scala测试中使用mock。使用特征和最小实现将让编译器指出这些错误。mock将这些检查移到运行时并混淆实际原因,就像在这个例子中一样。