ScalaTest:assert阻塞语句
我使用了一些带有ScalaTest:assert阻塞语句,scala,concurrency,future,reactive-programming,scalatest,Scala,Concurrency,Future,Reactive Programming,Scalatest,我使用了一些带有阻塞语句的代码: blocking { Thread.sleep(10*1000) } 有没有一种方法可以断言这个阻塞语句是给定的?或者换句话说:如果有人删除阻塞语句,我是否可以编写一个失败的测试 更新:如何在未来中使用时断言阻塞?尝试使用 你应该得到这样的东西: var blocked = false // flag to detect blocking val oldContext = BlockContext.current val myContext = ne
阻塞
语句的代码:
blocking {
Thread.sleep(10*1000)
}
有没有一种方法可以断言这个阻塞语句是给定的?或者换句话说:如果有人删除阻塞
语句,我是否可以编写一个失败的测试
更新:如何在未来中使用时断言阻塞?尝试使用
你应该得到这样的东西:
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
如果您想测试包装在未来中的代码,请更新如何使其工作(评论后续)
构建未来时,它的工厂方法需要显式执行代码块(函数),隐式执行执行上下文(通常为scala.concurrent.ExecutionContext.Implicits.global
)
稍后的代码块将被调度到执行上下文中,并将在其中一个线程中运行
现在,如果您只是将阻塞的代码片段包装到传递给BlockContext.withBlockContext
的代码块中,就像您在注释中建议的那样:
BlockContext.withBlockContext(myContext) {
Future {
blocking { Thread.sleep(100) }
}
}
。。。这将不起作用,因为当前线程将只执行Future
构造,传递给Future
的实际代码将从相关执行上下文(BlockContext.withBlockContext
在当前线程中检测阻塞s)在线程中执行
话虽如此,我可以建议您做以下三件事之一:
不要将要测试的代码包装到将来。如果您想测试一段代码是否使用阻塞
,只需这样做。
编写一个函数并对其进行测试,您可以将其传递给生产中的Future
假设出于某种原因,您无法避免在测试中创建未来。在这种情况下,您必须篡改构建未来时使用的执行上下文。
此代码示例演示了如何做到这一点(重用原始示例中的blocked
和myContext
):
如果您的Future
是间接创建的,例如,由于调用了您在测试中运行的其他函数,那么您必须以某种方式(可能使用依赖项注入)将模拟执行上下文拖动到创建Future
的任何位置,并在那里使用它来构建它
正如您所看到的,第一个选项是最简单的,如果可以,我建议您坚持使用它。谢谢您的提示!除非我在Future
s:BlockContext.withBlockContext(myContext){Future{blocking{Thread.sleep(100)}}}
中不使用blocking{}
你有办法解决它吗?
// 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)