使用 fire and forget Futures 进行 Scala 测试
Scala testing with fire and forget Futures
所以我有一些带有端点的服务器代码,我想在其中 运行 异步填充。为此,我正在使用期货。有导致结果的任务,但也有不会导致结果的昂贵 IO 任务,所以我在火中执行它们并忘记 Future 像这样:
import scala.concurrent.Future
val ec = scala.concurrent.ExecutionContext.global
Future {
Thread.sleep(10000)
println("Done")
}(ec)
println("Exiting now")
输出是:
import scala.concurrent.Future
ec: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl@2315ca48
res0: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@7d1e50cb
Exiting now
res1: Unit = ()
通常在服务器上这不是什么大问题,因为上下文在接收其他任务时保持 运行ning,因此 IO 可以完成。但是当我测试的时候,测试结束,里面的任务开始抛出,因为他们使用的服务变得不可用。
所以问题是:如何在不阻塞主要执行的情况下等待这些 fire and forget futures?
为了说明我的回答,假设您访问一些 fileService
以在即发即弃部分加载文件,并且您使用 Mockito(或其他模拟框架,想法保持不变)用于你的单元测试。然后,我将在解释中提到的代码看起来像这样:
class SystemUnderTest(val fileService: MyFileService) {
def testedMethod(): GoodResult = {
val file = // ... some logic to extract file ...
Future {
fileService.uploadFile(file)
}
// ... other logic returning an instance of GoodResult
}
}
然后,在你的测试中加入 org.scalatest.Eventually
并做出如下断言:
eventually {
verify(fileService).uploadFile(any())
}
它将确保主进程在验证上传服务已被调用(或 implicit patienceConfig
定义的超时已过期)之前不会退出。
当然,您始终可以选择 return 您不在生产代码中等待的 Future 而是在测试中等待它。
所以我有一些带有端点的服务器代码,我想在其中 运行 异步填充。为此,我正在使用期货。有导致结果的任务,但也有不会导致结果的昂贵 IO 任务,所以我在火中执行它们并忘记 Future 像这样:
import scala.concurrent.Future
val ec = scala.concurrent.ExecutionContext.global
Future {
Thread.sleep(10000)
println("Done")
}(ec)
println("Exiting now")
输出是:
import scala.concurrent.Future
ec: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl@2315ca48
res0: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@7d1e50cb
Exiting now
res1: Unit = ()
通常在服务器上这不是什么大问题,因为上下文在接收其他任务时保持 运行ning,因此 IO 可以完成。但是当我测试的时候,测试结束,里面的任务开始抛出,因为他们使用的服务变得不可用。
所以问题是:如何在不阻塞主要执行的情况下等待这些 fire and forget futures?
为了说明我的回答,假设您访问一些 fileService
以在即发即弃部分加载文件,并且您使用 Mockito(或其他模拟框架,想法保持不变)用于你的单元测试。然后,我将在解释中提到的代码看起来像这样:
class SystemUnderTest(val fileService: MyFileService) {
def testedMethod(): GoodResult = {
val file = // ... some logic to extract file ...
Future {
fileService.uploadFile(file)
}
// ... other logic returning an instance of GoodResult
}
}
然后,在你的测试中加入 org.scalatest.Eventually
并做出如下断言:
eventually {
verify(fileService).uploadFile(any())
}
它将确保主进程在验证上传服务已被调用(或 implicit patienceConfig
定义的超时已过期)之前不会退出。
当然,您始终可以选择 return 您不在生产代码中等待的 Future 而是在测试中等待它。