如何在 Scala 单元测试中指定异步调用的确切执行顺序?



我在 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

最新更新