gpt4 book ai didi

Scalatest 异步测试套件与最终和WhenReady (org.scalatest.concurrent)

转载 作者:行者123 更新时间:2023-12-05 00:45:51 28 4
gpt4 key购买 nike

我正在尝试使用 scalatest Asynchronous Test Suites ,但除了对设置超时的一些限制之外,我看不到测试套件实际添加了什么。

我想知道是否有人精通使用 scalatest 进行异步测试,可以快速解释异步测试套件和 org.scalatest.concurrent 之间的区别。 .异步测试套件实际上在 org.scalatest.concurrent 上添加了什么?一种方法比另一种更好吗?

最佳答案

我们比较以下 ScalaTest 工具来测试返回 Future 的代码年代:

  • Asynchronous style traits ,例如 AsyncFlatSpec
  • ScalaFutures
  • Eventually

  • 异步风格特征
    class AsyncSpec extends AsyncFlatSpec {
    ...
    Future(3).map { v => assert(v == 3) }
    ...
    }
  • 非阻塞
  • 我们可以在 Future 之前断言完成,即返回 Future[Assertion]而不是 Assertion
  • 线程安全
  • 单线程串行执行上下文
  • Futures按照启动顺序依次执行和完成
  • 用于将测试体中的任务排入队列的同一线程也用于之后执行它们
  • 断言可以映射到 Futures
  • 无需在测试体内部进行阻塞,即使用 Await , whenReady
  • 消除因线程不足导致的片状
  • 测试体中的最后一个表达式必须是 Future[Assertion]
  • 不支持测试体中的多个断言
  • 不能在测试体内使用阻塞构造,因为它会因为等待而永远挂起测试
    入队但从未开始的任务

  • 斯卡拉 future
    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 example.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 example.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

  • 请注意在串行执行模型中如何使用相同的线程并按顺序完成 future 。另一方面,
    在全局执行模型中使用了不同的线程, Future2Future1 之前完成, 这导致
    共享可变状态的竞争条件,这反过来又使测试失败。

    我们应该使用哪一个(IMO)?

    在单元测试中,我们应该使用返回 Futures 的模拟子系统。应该几乎立即完成,所以有
    不需要 Eventually在单元测试中。因此,选择是在异步样式和 ScalaFutures 之间。 .主要区别
    两者之间的区别在于前者不像后者那样是非阻塞的。如果可能的话,我们不应该阻塞,所以我们
    应该更喜欢像 AsyncFlatSpec 这样的异步样式.更大的区别是执行模型。异步样式
    默认情况下使用自定义串行执行模型,它提供共享可变状态的线程安全,不像全局
    经常与 ScalaFutures 一起使用的线程池支持的执行模型.总之,我的建议是我们使用异步风格
    特征,除非我们有充分的理由不这样做。

    关于Scalatest 异步测试套件与最终和WhenReady (org.scalatest.concurrent),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55487833/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com