如何测试期货是否在Scala中按顺序运行?

时间:2020-04-17 07:12:50

标签: scala unit-testing asynchronous future

假设我有以下方法:

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。

我的问题是,如何编写一个UNIT TEST来确保在计算b之前总是先计算a,而在计算c之前总是先计算b?我担心的是,如果有人不知道关于期货在斯卡拉的运作方式。他们可能会不小心使该代码异步运行。

我的意思是人们可以偶然做这样的事情,这使得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)
}

1 个答案:

答案 0 :(得分:0)

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

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仅在我们可以证明在编译时证明存在串行执行上下文的情况下才可以求值。由于体内只有一个线程,因此只有在前一个线程完成后才能强制启动期货。