scala – 用光滑和Postgres播放2.1单元测试
我想使用与生产中使用的相同的数据库设置为Play 2
Scala应用程序运行单元测试:与Postgres一起使用Slick.以下操作失败,出现“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,而不是代码中配置的信息. 解决方法
这是一个试探性的答案,因为我目前在Play 2.2.0上测试过,我无法使用MYSQL数据库重现您的错误.
我觉得你的代码中可能存在一个非常棘手的错误.首先,如果您探索Play,BoneCPPPlugin提供的DBPlugin实现: /** * 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()方法关闭连接池.所以很明显,您要向第二个测试示例提供一个已经停止的应用程序(因此它的插件已停止并且db connectin池已关闭). 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 } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |