【问题标题】:Why my Scala Async test never completes when I do Await.result?为什么当我执行 Await.result 时我的 Scala 异步测试从未完成?
【发布时间】:2020-09-26 07:00:52
【问题描述】:

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

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


    【解决方案1】:

    您将在 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)
        }
      }
    
    }
    

    【讨论】:

    • 解决方案 2 应该是解决方案 1,因为这是首选的做事方式。除非您知道自己在做什么,否则覆盖 EC 可能被认为是一种不好的做法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 2021-10-09
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多