在Mockito单元测试中抛出Exception时,Future的.recover不会被调用

问题描述 投票:2回答:2

以下代码返回Future。

val findUserFuture: Future[Option[User]] = userRepo.findOne(userKeys) 

然后我处理未来

findUserFuture.flatMap {....}
.recover{...}

fineOne返回FutureFuture包裹呼叫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])抛出异常,但测试用例停止了以下两个版画并且没有调用.recoverFuture

java.lang.RuntimeException was thrown.
java.lang.RuntimeException
scala mockito scalatest
2个回答
1
投票

这个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


0
投票

你无法模拟你想要测试的类型,模拟没有该类型的原始行为。

如果你想要只测试被测试类(或任何其他类型)的某些行为,你应该使用间谍,那么你只会做

when(spyUserRepository.getOneById(userKeys)).thenThrow(classOf[RuntimeException])

然后调用spyUserRepository.findOne(userKeys)并声明它返回一个失败的未来

也就是说,看起来你的责任有点混乱,我建议你再次设计你的设计,不得不求助于使用间谍,这对我来说就像是一个很大的代码味道。

© www.soinside.com 2019 - 2024. All rights reserved.