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