首页 > 解决方案 > 如何测试期货是否在Scala中按顺序运行?

问题描述

假设我有这个方法:

def callApis(f1, f2, f3):Future[Result] {
    for {
        a <- Future { f1 }
        b <- Future { f2 }
        c <- Future { f3 }
    } yield Result(a,b,c)
}

如果您熟悉 scala,您会知道 for 块中的行将按顺序执行。更具体地说,将首先计算 a。然后当我们得到 a 的结果时,代码将计算 b。然后当我们得到 b 的结果时,代码将计算 c。

我的问题是,如何编写一个单元测试来确保始终在计算 b 之前计算 a,并且始终在计算 c 之前计算 b?我担心的是,如果有人对 scala 中的期货如何运作知之甚少。他们可能会意外地使此代码异步运行。

我的意思是人们可能会不小心做这样的事情,这使得 a,b,c 被异步计算(我不希望人们这样做)

def callApis(f1, f2, f3):Future[Result] {
    val fut1 = Future { f1 }
    val fut2 = Future { f2 }
    val fut3 = Future { f3 }

    for {
        a <- fut1
        b <- fut2
        c <- fut3
    } yield Result(a,b,c)
}

标签: scalaunit-testingasynchronousfuture

解决方案


也许尝试定义一个单线程执行上下文,并在应该串行执行的块中要求它。例如,

trait SerialExecutionContext extends ExecutionContext {
  val singleThreadPool = Executors.newFixedThreadPool(1, (r: Runnable) => new Thread(r, s"single-thread-pool"))
  val serialEc = ExecutionContext.fromExecutor(singleThreadPool)
  override def execute(runnable: Runnable): Unit = serialEc.execute(runnable)
  override def reportFailure(cause: Throwable): Unit = serialEc.reportFailure(cause)
}


def callApis()(implicit ec: SerialExecutionContext): Future[Result] = {
  val fut1 = Future { ...doSomething... }
  val fut2 = Future { ...doSomething... }
  val fut3 = Future { ...doSomething... }

  for {
    a <- fut1
    b <- fut2
    c <- fut3
  } yield Result(a,b,c)
}

现在callApis只有当我们可以在编译时证明存在串行执行上下文时才能进行评估。由于在正文中我们只有一个可用线程,futures 只能在前一个线程完成后才强制启动。


推荐阅读