ScalaTest:断言阻塞语句

时间:2014-09-22 09:38:33

标签: scala concurrency future reactive-programming scalatest

我正在使用blocking语句的一些代码:

blocking {
    Thread.sleep(10*1000)
}

有没有办法断言这个blocking语句是给出的?或者换句话说:如果有人删除blocking语句,我可以写一个失败的测试吗?

更新:在Future s中使用时如何断言阻止?

1 个答案:

答案 0 :(得分:3)

尝试使用BlockContext

你应该得到这样的东西:

var blocked = false // flag to detect blocking

val oldContext = BlockContext.current
val myContext = new BlockContext {
  override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = {
    blocked = true
    oldContext.blockOn(thunk)
  }
}

BlockContext.withBlockContext(myContext) {
  blocking {} // block (or not) here
}

assert(blocked) // verify that blocking happened

如果您想测试Future中包含的代码(评论跟进)

,请确保其正常运行

构造Future时,它的工厂方法需要代码块(函数)来执行显式执行上下文 < strong>隐含(通常为scala.concurrent.ExecutionContext.Implicits.global)。

代码块稍后将被安排到执行上下文,并将在其中一个线程中运行。

现在,如果您只是将阻塞的代码段包装到传递给BlockContext.withBlockContext的Future内部代码块中,就像您在评论中建议的那样:

BlockContext.withBlockContext(myContext) {
  Future {
    blocking { Thread.sleep(100) }
  }
}

...这不起作用,因为您当前的线程只会进行Future构造,传递给Future的实际代码将在相关执行上下文的线程中执行(BlockContext.withBlockContext检测{ {1}}在当前线程中。)

说完了,我建议你做三件事之一:

  1. 不要将要测试的代码包装到Future中。如果你想测试一段代码是否使用blocking - 就这样做 编写一个函数并对其进行测试,您可以将其传递给生产中的blocking

  2. 让我们假设您出于某种原因无法避免在测试中创建Future。在这种情况下,您将不得不篡改构建未来时使用的执行上下文 此代码示例演示了如何执行此操作(从原始示例重用Futureblocked):


  3. myContext
    1. 如果您的// execution context that submits everything that is passed to it to global execution context // it also wraps any work submited to it into block context that records blocks implicit val ec = new ExecutionContext { override def execute(runnable: Runnable): Unit = { ExecutionContext.Implicits.global execute new Runnable { override def run(): Unit = { BlockContext.withBlockContext(myContext) { runnable.run() } } } } override def reportFailure(t: Throwable): Unit = { ExecutionContext.Implicits.global.reportFailure(t) } } // this future will use execution context defined above val f = Future { blocking {} // block (or not) here } Await.ready(f, scala.concurrent.duration.Duration.Inf) assert(blocked) 间接创建,例如,因此调用您在测试中运行的其他函数,那么您将不得不以某种方式(可能使用依赖注入)将您的模拟执行上下文拖入创建Future的地方,并在那里使用它来构建它。
    2. 正如您所看到的,第一个选项是最简单的选项,如果可以,我建议坚持使用。