以下代码返回Future。
val findUserFuture: Future[Option[User]] = userRepo.findOne(userKeys)
然后我处理未来
findUserFuture.flatMap {....}
.recover{...}
fineOne
返回Future
和Future
包裹呼叫getOneById
def findOne(userKeys:UserKeys):Future[Option[User]] = {
Future{
//val loginInfo:LoginInfo = LoginInfo(userKeys.providerID,userKeys.authProvider)
val userOption:Option[User] = getOneById(userKeys)
userOption
}
}
我想如果Future
返回的findOne
失败,则会调用recover,即抛出异常。所以我通过让getOneById
抛出异常来模拟它。
when(mockUserRepository.findOne(userKeys)).thenReturn(Future(Some(user)))
when(mockUserRepository.getOneById(userKeys)).thenThrow(classOf[RuntimeException]) //simulating database error
但是单元测试没有抛出异常,测试继续使用值Future(Some(User))
。
我也尝试从findOne
- when(mockUserRepository.findOne(userKeys)).thenThrow(classOf[RuntimeException])
抛出异常,但测试用例停止了以下两个版画并且没有调用.recover
的Future
java.lang.RuntimeException was thrown.
java.lang.RuntimeException
这个findUserFuture: Future[Option[User]]
或userRepo.findOne
返回未来,因此你需要在你的模拟中返回Future.failed
。对于前者
when(mockUserRepository.findOne(userKeys)).thenReturn(Future(Some(user)))
when(mockUserRepository.getOneById(userKeys)).thenReturn(Future.failed(new RuntimeException("network failure"))
找到以下完整的工作测试来模拟您的用例:
test("mock future test") {
case class User(name: String)
case class UserNotFoundException(name: String) extends Exception
trait UserRepo {
def findOne(name: String): Future[Option[User]]
}
val name = "bob"
val dummyUser = User("dummy")
val userRepo = mock[UserRepo]
when(userRepo.findOne(name)).thenReturn(Future.failed(new RuntimeException()))
val userF = userRepo
.findOne(name)
.flatMap {
case Some(user) ⇒ Future.successful(user)
case None ⇒ Future.failed(UserNotFoundException(name))
}
.recover {
case NonFatal(_) ⇒ dummyUser
}
userF.futureValue shouldBe dummyUser
}
when(mockUserRepository.findOne(userKeys)).thenCallRealMethod()
when(mockUserRepository.getOneById(userKeys)).thenThrow(classOf[RuntimeException])
注意thenCallRealMethod()
在这里,早些时候你嘲笑findOne
以成功的价值返回未来,这意味着原始方法没有被调用,而这反过来又没有调用getOneById
你无法模拟你想要测试的类型,模拟没有该类型的原始行为。
如果你想要只测试被测试类(或任何其他类型)的某些行为,你应该使用间谍,那么你只会做
when(spyUserRepository.getOneById(userKeys)).thenThrow(classOf[RuntimeException])
然后调用spyUserRepository.findOne(userKeys)
并声明它返回一个失败的未来
也就是说,看起来你的责任有点混乱,我建议你再次设计你的设计,不得不求助于使用间谍,这对我来说就像是一个很大的代码味道。