我的应用程序基于Scala Play框架,并且具有一个计划的Job,该Job在每次加载应用程序时运行:
//代码段:
actorSystem.scheduler.schedule(initialDelay = 0.second, interval = intervalSeconds.second)
在测试过程中,如果我启用了计划的作业,则所有测试都可以正常完成,并且结果通过(绿色),但是我在日志中随机看到一个异常:
[TaskInvocation]在实现器具有后尝试实现流 已关闭java.lang.IllegalStateException:尝试实现 实现器关闭后的流 akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:424) 在 akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:417) 在 akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:408) 在akka.stream.scaladsl.RunnableGraph.run(Flow.scala:556)在 akka.stream.scaladsl.Source.runWith(Source.scala:103)在 play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:203)在 mockws.FakeWSRequestHolder.executeResult(FakeWSRequestHolder.scala:118) 在嘲笑.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:103) 在嘲笑.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:188) 在嘲笑.FakeWSRequestHolder.get(FakeWSRequestHolder.scala:181)
我正在使用Web服务模拟库:https://github.com/leanovate/play-mockws 该错误似乎与该库在测试期间如何使用和释放ActorSystem实现器实例有关。对于与actor系统相关的测试配置,我有:
MockWSHelpers中的代码:
trait MockWSHelpers {
private val actorSystem: ActorSystem = actor.ActorSystem("unit-testing")
implicit val materializer: ActorMaterializer = ActorMaterializer()(actorSystem)
val BodyParser: PlayBodyParsers = PlayBodyParsers()
val Action: DefaultActionBuilder = DefaultActionBuilder(BodyParser.anyContent)
def shutdownHelpers(): Unit = {
materializer.shutdown()
Await.result(actorSystem.terminate(), 3.minutes)
}
}
object MockWSHelpers extends MockWSHelpers {
sys addShutdownHook {
shutdownHelpers()
}
}
所有测试都将继承的基本测试类:
abstract class BaseDomainTest extends PlaySpec with MockitoSugar with MockWSHelpers with BeforeAndAfterAll {
override def afterAll(): Unit = {
shutdownHelpers()
}
}
域测试类将扩展BaseDomainTest,例如:
@RunWith(classOf[JUnitRunner])
class MyTestDomainControllerSpec extends BaseDomainTest {
我的印象是,有时排定的作业在MockWSHelpers的关闭挂钩结束之前未完成,并且引发了异常,当它在此之前完成则没有异常。
如何避免上述异常?
替代方法:
一种选择是只在测试期间完全禁用计划的作业,然后将其内部业务逻辑移到完全独立的类中。示例:
scheduledTask:
actorSystem.scheduler.schedule(initialDelay = 0.second,interval = intervalSeconds.second){ 如果(config.isJobEnabled){ myBusinessObject.execute() } }
在这种情况下,只需单独测试myBusinessObject.execute()
,并且在测试过程中不要启用计划的任务。