为什么当我执行Await.result时,我的Scala异步测试从未完成?

问题描述 投票:2回答:2

我创建了一个简单的测试场景,显示了以下内容:

class Test extends AsyncFunSuite {

  test("async test") {
    val f = Future {
      val thread = new Thread {
        override def run(): Unit = {
          println("OKAYY")
        }
      }
      thread.start()
    }

    Await.result(f, Duration.Inf)
    Future {
      assert(true)
    }
  }

}

执行此操作时,测试将永远运行并且永远不会完成。

scala asynchronous future scalatest
2个回答
4
投票

您会在ScalaTest中的所有异步测试(AsyncFeatureSpec,AsyncFlatSpec,AsyncFreeSpec,AsyncFunSpec,AsyncFunSuite,AsyncWordSpec)中看到相同的行为。

原因是ScalaTest中的默认执行上下文是串行执行上下文。您可以在此处了解更多信息:https://www.scalatest.org/user_guide/async_testing。我总结了以下要点。

在JVM上使用ScalaTest的串行执行上下文将确保产生从测试主体返回的Future [Assertion]的相同线程也用于执行在执行测试主体时赋予执行上下文的任何任务,并且该线程不会在测试完成之前,可以执行其他任何操作。

但是,这种线程限制策略的确意味着,当您在JVM上使用默认执行上下文时,必须确保不要在测试主体中阻塞,以等待任务由执行上下文完成。如果您阻止,则测试将永远无法完成。

解决方案1:覆盖执行上下文

implicit override def executionContext = scala.concurrent.ExecutionContext.Implicits.global

解决方案2:链接

class Test extends AsyncFunSuite {

  test("async test") {
    val f = Future {
      val thread = new Thread {
        override def run(): Unit = {
          println("OKAYY")
        }
      }
      thread.start()
    }

    f.map { _ =>
      assert(true)
    }
  }

}

0
投票

异步样式特征提供serial execution context

private final val serialExecutionContext: ExecutionContext = new concurrent.SerialExecutionContext
implicit def executionContext: ExecutionContext = serialExecutionContext

只是将作业放在队列中,并使用主线程一个接一个地执行它们,也就是说,只有一个线程可用。因此,在任何时候阻塞该线程都会阻塞整个测试套件。但是请注意,对于以下three reasons],此选择为根据设计

  • Performance:与仅并行运行套件相比,并行运行测试和套件不会显着提高性能。
  • Thread-safety
  • :如果多个线程同时在同一套件中运行,则需要确保多个线程对任何可变夹具对象的访问都已同步]]
  • Starvation:测试体返回时,异步样式的测试不需要完成,因为测试体返回Future [Assertion]。此Future [Assertion]通常代表尚未完成的测试。结果,当使用由线程池支持的更传统的执行上下文时,与线程池中的线程相比,您可能会启动更多的并发执行测试。您从相同的有限线程池中争夺线程的并发执行测试越多,由于超时而导致测试间歇性地失败的可能性就越大。
  • 因此,用线程池支持的执行上下文替换串行执行上下文可能会导致进行flakey测试,以换取没有真正的性能提升。

    我在https://stackoverflow.com/a/55526334/5205022提供了一个示例和一些相关信息

© www.soinside.com 2019 - 2024. All rights reserved.