我正在尝试使用scalatest异步测试套件,但是除了设置超时方面有一些限制之外,我没有看到测试套件实际上添加了什么。
我想知道是否有人精通scalatest进行异步测试,可以快速解释异步测试套件和org.scalatest.concurrent之间的区别。那是测试套件实际上添加了org.scalatest.concurrent吗?否则,最好是用一种方法代替另一种方法
答案 0 :(得分:2)
我们比较以下ScalaTest工具来测试返回Future
s的代码:
class AsyncSpec extends AsyncFlatSpec {
...
Future(3).map { v => assert(v == 3) }
...
}
Future
完成之前断言,即返回Future[Assertion]
而不是Assertion
Futures
按照启动顺序并依次执行并完成Futures
Await
,whenReady
Future[Assertion]
class ScalaFuturesSpec extends FlatSpec with ScalaFutures {
...
whenReady(Future(3) { v => assert(v == 3) }
...
}
Future
才能返回Assertion
scala.concurrent.ExecutionContext.Implicits.global
一起使用,它是一个
多线程并行执行池Assertion
class EventuallySpec extends FlatSpec with Eventually {
...
eventually { assert(Future(3).value.contains(Success(3))) }
...
}
Futures
Futures
时,很有可能会使用全局执行上下文scalatest-async-testing-comparison是一个示例 展示了两种执行模型的差异。
给出以下测试体
val f1 = Future {
val tmp = mutableSharedState
Thread.sleep(5000)
println(s"Start Future1 with mutableSharedState=$tmp in thread=${Thread.currentThread}")
mutableSharedState = tmp + 1
println(s"Complete Future1 with mutableSharedState=$mutableSharedState")
}
val f2 = Future {
val tmp = mutableSharedState
println(s"Start Future2 with mutableSharedState=$tmp in thread=${Thread.currentThread}")
mutableSharedState = tmp + 1
println(s"Complete Future2 with mutableSharedState=$mutableSharedState")
}
for {
_ <- f1
_ <- f2
} yield {
assert(mutableSharedState == 2)
}
让我们考虑AsyncSpec
对ScalaFuturesSpec
的输出
testOnly示例。AsyncSpec:
Start Future1 with mutableSharedState=0 in thread=Thread[pool-11-thread-3-ScalaTest-running-AsyncSpec,5,main]
Complete Future1 with mutableSharedState=1
Start Future2 with mutableSharedState=1 in thread=Thread[pool-11-thread-3-ScalaTest-running-AsyncSpec,5,main]
Complete Future2 with mutableSharedState=2
testOnly示例。ScalaFuturesSpec:
Start Future2 with mutableSharedState=0 in thread=Thread[scala-execution-context-global-119,5,main]
Complete Future2 with mutableSharedState=1
Start Future1 with mutableSharedState=0 in thread=Thread[scala-execution-context-global-120,5,main]
Complete Future1 with mutableSharedState=1
请注意在串行执行模型中如何使用相同的线程以及如何按顺序完成期货。另一方面,
在全局执行模型中,使用了不同的线程,并且在Future2
之前完成了Future1
,这导致
共享可变状态下的竞争状态,这又导致测试失败。
在单元测试中,我们应该使用模拟子系统,其中返回的Futures
应该立即完成,因此
在单元测试中不需要Eventually
。因此,选择是在异步样式和ScalaFutures
之间。主要区别
两者之间的区别在于前者与后者不同。如果可能的话,我们绝不应该阻止,所以我们
应该更喜欢AsyncFlatSpec
之类的异步样式。执行模型还有更大的不同。异步样式
默认情况下,使用自定义串行执行模型,该模型在共享的可变状态下提供线程安全,这与全局
线程池支持的执行模型通常与ScalaFutures
一起使用。总之,我的建议是我们使用异步样式
特质,除非我们有充分的理由不这样做。