【问题标题】:Play 2.1 Unit Test With Slick and Postgres使用 Slick 和 Postgres 玩 2.1 单元测试
【发布时间】:2013-06-21 14:27:19
【问题描述】:

我想为 Play 2 Scala 应用程序运行单元测试,使用的数据库设置与生产环境中使用的相同:Slick with Postgres。以下失败并显示“java.sql.SQLException:尝试从已关闭的池中获取连接”。第二次测试。

package controllers

import org.specs2.mutable._
import play.api.db.DB
import play.api.Play.current
import play.api.test._
import play.api.test.Helpers._
import scala.slick.driver.PostgresDriver.simple._

class BogusTest extends Specification {

  def postgresDatabase(name: String = "default", 
                       options: Map[String, String] = Map.empty): Map[String, String] =
    Map(
      "db.test.driver"   -> "org.postgresql.Driver",
      "db.test.user"     -> "postgres",
      "db.test.password" -> "blah",
      "db.test.url"      -> "jdbc:postgresql://localhost/blah"
    )

  def fakeApp[T](block: => T): T =
    running(FakeApplication(additionalConfiguration = 
      postgresDatabase("test") ++ Map("evolutionplugin" -> "disabled"))) {
        def database = Database.forDataSource(DB.getDataSource("test"))
        database.withSession { implicit s: Session => block }
      }

  "Fire 1" should {
    "do something" in fakeApp {
      success
    }
  }

  "Fire 2" should {
    "do something else" in fakeApp {
      success
    }
  }
}

我这样运行测试:

$ play -Dconfig.file=`pwd`/conf/dev.conf "test-only controllers.BogusTest"

另外两个谜团:

1) 所有测试都运行,即使我只要求运行 BogusTest

2) 始终使用application.conf,而不是def.conf,驱动信息来自application.conf,而不是代码中配置的信息。

【问题讨论】:

  • 查看stackoverflow.com/questions/15399161/… 了解如何使用test 指定不同的配置文件。
  • 谢谢,看起来这应该解决神秘问题 #2。你能解释一下主要问题吗?
  • 我也遇到了同样的问题。即使不使用 specs2 中的 Around 特征,并且简单地包裹在 in{ running(fakeApp) {Database.forDataSource(DB.getDataSource()) withSession {}} } 内也会产生此异常。
  • 我想我有你的答案,但是请发布一个带有 h2 和所有依赖项的 github 项目,以便我可以在向论坛发送垃圾邮件之前进行测试:)
  • 在 dev conf 中启用日志记录然后发布测试运行的日志可能会有所帮助。

标签: scala playframework playframework-2.1 slick specs2


【解决方案1】:

这是一个暂定答案,因为我目前在 play 2.2.0 上进行了测试,但我无法使用 MYSQL 数据库重现您的错误。

我觉得您的代码中可能存在一个非常棘手的错误。首先,如果你探索 Play 提供的 DBPlugin 实现,BoneCPPPlugin:

  /**
   * Closes all data sources.
   */
  override def onStop() {
    dbApi.datasources.foreach {
      case (ds, _) => try {
        dbApi.shutdownPool(ds)
      } catch { case NonFatal(_) => }
    }
    val drivers = DriverManager.getDrivers()
    while (drivers.hasMoreElements) {
      val driver = drivers.nextElement
      DriverManager.deregisterDriver(driver)
    }
  }

您会看到 onStop() 方法关闭了连接池。所以很明显,您正在向第二个测试示例提供一个已经停止的应用程序(因此它的插件被停止并且数据库连接池关闭)。

Scalatests 和 specs2 并行运行测试,您可以依赖测试助手,因为它是线程安全的:

  def running[T](fakeApp: FakeApplication)(block: => T): T = {
        synchronized {
          try {
            Play.start(fakeApp)
            block
          } finally {
            Play.stop()
            play.api.libs.ws.WS.resetClient()
          }
        }
      }

但是,当你这样做时

DB.getDataSource("test")

来自Play的源代码:

  def getDataSource(name: String = "default")(implicit app: Application): DataSource = app.plugin[DBPlugin].map(_.api.getDataSource(name)).getOrElse(error)

所以这里有一个隐含的,不会被解析为 FakeApplication(它不是范围内的隐含!!!),而是Play.current,在第二种情况下,这似乎不是你的样子期待它,Play.current 仍然指向 FakeApplication 的前一个实例:它可能取决于闭包中如何捕获隐式

但是,如果你重构 fakeApp 方法,你可以确保你刚刚创建的应用程序用于解决隐式(你总是可以显式地为隐式参数设置值)

  def fakeApp[T](block: => T): T = {
    val fakeApplication = FakeApplication(additionalConfiguration =
      postgresDatabase("test") ++ Map("evolutionplugin" -> "disabled"))
      running(fakeApplication) {
        def database = Database.forDataSource(DB.getDataSource("test")(fakeApplication))
        database.withSession { implicit s: Session => block }
      }
  }

【讨论】:

  • 埃德蒙多,出色的侦探!这确实使事情向前发展。不幸的是,从命令行运行时,我现在得到“RuntimeException:没有启动的应用程序”。我对所有相关文件做了一个要点gist.github.com/mslinn/8046542
  • 你能在 github repo 上提供一个 sbt 项目吗?我缺少在 test.conf 中导入的 application.conf 并且很难调试。在您的要点中,我看到您仍然将 play.api.Play.current 作为导入。我会删除它,看看会发生什么
  • 用我在这里所做的更改再试一次 - gist.github.com/drstevens/8048116/…
  • 我没有你所有的model.training._,请在github上提供一个独立的项目,我可以克隆调试。我永远无法用你现在提供的唯一信息进一步帮助你,因为我无法运行你的代码
  • 正如我所说,进一步调查的唯一方法是您提供一个 github repo
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-07
  • 1970-01-01
  • 2017-10-01
  • 2018-09-10
  • 2014-03-23
  • 1970-01-01
相关资源
最近更新 更多