播放报告在关闭后无法获取ClosableLazy值

时间:2015-01-16 14:21:04

标签: scala playframework-2.0 reactivemongo

我正在尝试在Play / Scala / ReactiveMongo项目中运行规范测试。安装程序是这样的:

class FeaturesSpec extends Specification {

  "Features controller" should {
    "create feature from JSON request" in withMongoDb { app =>
      // do test
    }
}

使用MongoDbFixture如下:

object MongoDBTestUtils {
  def withMongoDb[T](block: Application => T): T = {
    implicit val app = FakeApplication(
      additionalConfiguration = Map("mongodb.uri" -> "mongodb://localhost/unittests")
    )
    running(app) {
      def db = ReactiveMongoPlugin.db
      try {
        block(app)
      } finally {
        dropAll(db)
      }
    }
  }

  def dropAll(db: DefaultDB) = {
    Await.ready(Future.sequence(Seq(
      db.collection[JSONCollection]("features").drop()
    )), 2 seconds)
  }
}

当测试运行时,日志非常嘈杂,抱怨资源已经关闭。虽然测试工作正常,但这很奇怪,我想知道为什么会发生这种情况以及如何解决它。

错误:

[info] application - ReactiveMongoPlugin stops, closing connections...
[warn] play - Error stopping plugin
java.lang.IllegalStateException: Can't get ClosableLazy value after it has been closed
    at play.core.ClosableLazy.get(ClosableLazy.scala:49) ~[play_2.11-2.3.7.jar:2.3.7]
    at play.api.libs.concurrent.AkkaPlugin.applicationSystem(Akka.scala:71) ~[play_2.11-2.3.7.jar:2.3.7]
    at play.api.libs.concurrent.Akka$$anonfun$system$1.apply(Akka.scala:29) ~[play_2.11-2.3.7.jar:2.3.7]
    at play.api.libs.concurrent.Akka$$anonfun$system$1.apply(Akka.scala:29) ~[play_2.11-2.3.7.jar:2.3.7]
    at scala.Option.map(Option.scala:145) [scala-library-2.11.4.jar:na]

2 个答案:

答案 0 :(得分:1)

该异常意味着您在应用程序停止后使用ReactiveMongo插件。

您可能想尝试使用Around

class withMongoDb extends Around with Scope {
  val db = ReactiveMongoPlugin.db

  override def around[T: AsResult](t: => T): Result = try {
    val res = t
    AsResult.effectively(res)
  } finally {
    ...
  }
}

您还应该查看Flapdoodle Embedded Mongo,因为在测试IIRC后您不必删除数据库。

答案 1 :(得分:0)

可能会出现此问题,因为您的测试练习了引用已关闭的MongoDB实例的代码。运行每个Play Specs2测试后,MongoDb连接将被重置,因此您的第一个测试可能会通过,但后续测试可能会对已关闭的实例保持陈旧的引用,从而导致失败。

解决此问题的一种方法是确保在您的应用程序中满足以下条件:

  • 避免对MongoDb数据库资源使用val或lazy val
  • (重新)在应用程序启动时初始化所有数据库引用。

我写了一篇blog帖子,描述了Play控件上下文中问题的解决方案。