The following code returns a Future.
val findUserFuture: Future[Option[User]] = userRepo.findOne(userKeys)
Then I process the Future
findUserFuture.flatMap {....}
.recover{...}
fineOne returns the Future and the Future wraps call to getOneById
def findOne(userKeys:UserKeys):Future[Option[User]] = {
Future{
//val loginInfo:LoginInfo = LoginInfo(userKeys.providerID,userKeys.authProvider)
val userOption:Option[User] = getOneById(userKeys)
userOption
}
}
I suppose that recover will be called if Future returned by findOne fails i.e. throws an Exception. So I am simulating that by making getOneById throw an exception.
when(mockUserRepository.findOne(userKeys)).thenReturn(Future(Some(user)))
when(mockUserRepository.getOneById(userKeys)).thenThrow(classOf[RuntimeException]) //simulating database error
But the unit test doesn't throw an exception and the test proceeds using value Future(Some(User)).
I also tried throwing the exception from findOne - when(mockUserRepository.findOne(userKeys)).thenThrow(classOf[RuntimeException]) but the test case stops
with the following two prints and the .recover of the Future is not called
java.lang.RuntimeException was thrown.
java.lang.RuntimeException
This findUserFuture: Future[Option[User]] or userRepo.findOne returns future,
hence you need to return Future.failed in your mock.
For ex.
when(mockUserRepository.findOne(userKeys)).thenReturn(Future(Some(user)))
when(mockUserRepository.getOneById(userKeys)).thenReturn(Future.failed(new RuntimeException("network failure"))
Find below complete working test to simulate your use case :
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])
Notice thenCallRealMethod() here, earlier you were mocking findOne to return future with successful value which means original method was not getting called which in turn was not calling getOneById
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With