我在 Scala 中为期货编写了许多不同的单元测试。 所有异步调用都使用执行上下文。 为了确保异步调用始终以相同的顺序执行,我需要延迟一些相当困难的任务,并且会减慢测试速度。 执行程序可能仍(取决于其实现(先于其他任务完成某些任务。
测试具有特定执行顺序的并发代码的最佳方法是什么?例如,我有以下测试用例:
"firstSucc" should "complete the final future with the first one" in {
val executor = getExecutor
val util = getUtil
val f0 = util.async(executor, () => 10)
f0.sync
val f1 = util.async(executor, () => { delay(); 11 })
val f = f0.firstSucc(f1)
f.get should be(10)
}
其中延迟def delay() = Thread.sleep(4000)
,sync
同步未来(调用Await.ready(future, Duration.Inf)
(。 这就是我想确保 f0 已经完成并且 f1 在 f0 之后完成的方式。完成 f0 是不够的,因为firstSucc
可能会洗牌期货。因此,f1 应延迟到检查f.get
之后。
另一个想法是从承诺中创建期货并在某个时间点完成它们:
"firstSucc" should "complete the final future with the first one" in {
val executor = getExecutor
val util = getUtil
val f0 = util.async(executor, () => 10)
val p = getPromise
val f1 = p.future
val f = f0.firstSucc(f1)
f.get should be(10)
p.trySuccess(11)
}
有没有更简单/更好的方法来定义执行顺序?也许是另一个可以配置提交任务顺序的执行服务? 对于这种特定情况,将第二个期货推迟到检查结果之后可能就足够了,但在某些情况下,所有期货都必须按一定的顺序完成。
完整的代码可以在这里找到:https://github.com/tdauth/scala-futures-promises
测试用例是此类的一部分:https://github.com/tdauth/scala-futures-promises/blob/master/src/test/scala/tdauth/futuresandpromises/AbstractFutureTest.scala
这个问题可能是相关的,因为Scala可以使用Java Executor Services:使用ExecutorService控制任务执行顺序。
对于大多数简单的情况,我会说单线程执行器就足够了 - 如果你一个接一个地开始你的期货,它们将被串行执行,并以相同的顺序完成。
但看起来你的问题实际上比你描述的要复杂得多:你不仅在寻找一种方法来确保一个未来比另一个更晚完成,而且一般来说,使一系列任意事件以特定的顺序发生。Fr 示例,您问题中的片段,验证第二个未来在第一个未来完成后开始(顺便说一句,我不知道在这种情况下delay
是做什么的(。
您可以使用eventually
等待特定事件发生,然后再继续:
val f = Future(doSomething)
eventually {
someFlag shouldBe true
}
val f1 = Future(doSomethingElse)
eventually {
f.isCompleted shouldBe true
}
someFlag = false
eventually {
someFlag shouldBe true
}
f1.futureValue shoudlBe false