我正在使用blocking
语句的一些代码:
blocking {
Thread.sleep(10*1000)
}
有没有办法断言这个blocking
语句是给出的?或者换句话说:如果有人删除blocking
语句,我可以写一个失败的测试吗?
更新:在Future
s中使用时如何断言阻止?
答案 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}}在当前线程中。)
说完了,我建议你做三件事之一:
不要将要测试的代码包装到Future中。如果你想测试一段代码是否使用blocking
- 就这样做
编写一个函数并对其进行测试,您可以将其传递给生产中的blocking
。
让我们假设您出于某种原因无法避免在测试中创建Future。在这种情况下,您将不得不篡改构建未来时使用的执行上下文
此代码示例演示了如何执行此操作(从原始示例重用Future
和blocked
):
myContext
// 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
的地方,并在那里使用它来构建它。正如您所看到的,第一个选项是最简单的选项,如果可以,我建议坚持使用。