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



我正在为代码的一些异步部分编写单元测试(返回Futures(,这些部分还需要模拟Scala对象。根据这些文档,我可以成功地模拟对象的函数。我的问题源于withObjectMocked[FooObject.type]返回Unit的事实,其中scalatest中的异步测试需要返回AssertionFuture[Assertion]。为了解决这个问题,我在测试中创建了var,并在发送给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
}
}

那么,我的问题是,有没有一种更好/更干净/更惯用的方法来编写异步测试,模拟对象,而无需跳过这一环节?出于某种原因,我认为使用AsyncMockitoSugar而不是MockitoSugar会解决这个问题,但withObjectMocked仍然返回Unit。这可能是一个bug和/或功能请求的候选者(withObjectMocked的异步版本返回的是功能块的值,而不是Unit(吗?还是我错过了如何完成这类任务?

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

当您使用mockObject时,您可以有效地强制覆盖此var(代码负责恢复原始代码,因此如果您愿意,可以将其作为"资源"使用语法(。

因为这个var是全局/共享的,如果你有多线程测试,你会有随机行为,这就是为什么没有提供异步API的主要原因。

无论如何,这是一个最后的工具,每次你发现自己在使用它时,你都应该停下来问问自己,你的代码是否有什么问题,这里有很多模式可以帮助你(比如注入依赖项(,所以你很少需要这样做。

最新更新