mir*_*val 2 concurrency scala future
所以我有一些带有端点的服务器代码,我想在其中异步运行东西。为此,我正在使用期货。有些任务会产生结果,但也有昂贵的 IO 任务不会产生结果,所以我在火中执行它们并忘记了 Future,如下所示:
import scala.concurrent.Future
val ec = scala.concurrent.ExecutionContext.global
Future {
Thread.sleep(10000)
println("Done")
}(ec)
println("Exiting now")
Run Code Online (Sandbox Code Playgroud)
其输出为:
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 = ()
Run Code Online (Sandbox Code Playgroud)
通常在服务器上这并不是什么大问题,因为上下文在接收其他任务时保持运行,因此 IO 可以完成。但是当我测试时,测试完成并且里面的任务开始抛出,因为他们使用的服务变得不可用。
所以问题是:我如何等待这些“即发即忘”的期货,而又不会阻止我的主要执行?
为了说明我的答案,让我们假设您访问一些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
}
}
Run Code Online (Sandbox Code Playgroud)
然后,在您的测试中混合org.scalatest.Eventually并做出如下断言:
eventually {
verify(fileService).uploadFile(any())
}
Run Code Online (Sandbox Code Playgroud)
它将确保主进程在验证上传器服务已被调用(或 定义的超时已implicit patienceConfig过期)之前不会退出。
当然,您始终可以选择返回您不在生产代码中等待的 Future 并在测试中等待它。