为什么当我执行 Await.result 时,我的 Scala 异步测试永远不会完成?

Sar*_*smi 3 asynchronous scala future scalatest

我创建了一个简单的测试场景来显示这一点:

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)
    }
  }

}
Run Code Online (Sandbox Code Playgroud)

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

Sar*_*smi 5

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

\n

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

\n
\n

在 JVM 上使用 ScalaTest\ 的串行执行上下文将确保生成从测试主体返回的 Future[Assertion] 的同一线程也用于执行在执行测试主体\xe2\x80\ 时给予执行上下文的任何任务x94and 该线程在测试完成之前将不允许执行任何其他操作。

\n

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

\n
\n

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

\n
implicit override def executionContext = scala.concurrent.ExecutionContext.Implicits.global\n
Run Code Online (Sandbox Code Playgroud)\n

解决方案 2:链接

\n
class Test extends AsyncFunSuite {\n\n  test("async test") {\n    val f = Future {\n      val thread = new Thread {\n        override def run(): Unit = {\n          println("OKAYY")\n        }\n      }\n      thread.start()\n    }\n\n    f.map { _ =>\n      assert(true)\n    }\n  }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n