使用 mockito 使用 scalatest 和 mocking 对象进行异步测试的模式

Pattern for async testing with scalatest and mocking objects with mockito

我正在为我的代码的某些异步部分(返回 Futures)编写单元测试,这些代码还涉及模拟 Scala 对象的需要。 按照these docs,我可以成功模拟对象的功能。我的问题源于 withObjectMocked[FooObject.type] returns Unit,其中 scalatest 中的异步测试需要返回 AssertionFuture[Assertion]。为了解决这个问题,我在我的测试中创建了 vars,我在发送到 withObjectMocked[FooObject.type] 的函数中重新分配它,最终看起来像这样:

class SomeTest extends AsyncWordSpec with Matchers with AsyncMockitoSugar with ResetMocksAfterEachAsyncTest {
      "wish i didn't need a temp var" in {
        var ret: Future[Assertion] = Future.failed(new Exception("this should be something")) // <-- note the need to create the temp var

        withObjectMocked[SomeObject.type] {
          when(SomeObject.someFunction(any)) thenReturn Left(Error("not found"))

          val mockDependency = mock[SomeDependency]
          val testClass = ClassBeingTested(mockDependency)

          ret = testClass.giveMeAFuture("test_id") map { r =>
              r should equal(Error("not found"))
          } // <-- set the real Future[Assertion] value here
        }

        ret // <-- finally, explicitly return the Future
      }
}

那么我的问题是,是否有一种 better/cleaner/more 惯用的方法来编写模拟对象的异步测试而无需跳过这个环节?出于某种原因,我认为使用 AsyncMockitoSugar 而不是 MockitoSugar 会为我解决这个问题,但 withObjectMocked 仍然 returns Unit。这可能是一个错误 and/or 功能请求的候选(withObjectMocked 的异步版本返回功能块的值而不是 Unit)?或者我是否缺少如何完成此类任务?

您应该避免在多线程环境中使用 mockObject,因为它不能很好地发挥作用。 这是因为 object 代码存储为单例实例,因此它实际上是全局的。

当您使用 mockObject 时,您实际上是在强行覆盖此 var(代码负责恢复原始代码,因此如果需要,可以将其作为“资源”使用) .

因为这个 var 是 global/shared,如果你有多线程测试,你最终会出现随机行为,这就是为什么没有提供异步 API 的主要原因。

无论如何,这是不得已的工具,每次你发现自己在使用它时,你应该停下来问问自己,如果你的代码没有任何问题,有很多模式可以帮助你在这里(比如注入依赖项),所以你应该很少需要这样做。