问题 如何在Slick和Play的测试中应用手动演变! 2.4


我想在每个测试文件的开头手动运行我的evolution脚本。我正在玩Play! 2.4和Slick 3。

根据文档,走的路似乎是:

Evolutions.applyEvolutions(database)

但我无法获得我的数据库实例。在里面 文件  play.api.db.Databases 导入是为了获取数据库实例,但如果我尝试导入它,我会收到此错误: object Databases is not a member of package play.api.db

如何获取我的数据库实例以运行evolution脚本?

编辑: 如评论中所述,这里是给出错误的完整源代码:

import models._
import org.scalatest.concurrent.ScalaFutures._
import org.scalatest.time.{Seconds, Span}
import org.scalatestplus.play._
import play.api.db.evolutions.Evolutions
import play.api.db.Databases

class TestAddressModel extends PlaySpec with OneAppPerSuite {
   lazy val appBuilder = new GuiceApplicationBuilder()
   lazy val injector = appBuilder.injector()
   lazy val dbConfProvider = injector.instanceOf[DatabaseConfigProvider]

  def beforeAll() = {
    //val database: Database = ???
    //Evolutions.applyEvolutions(database)
  }

  "test" must { 
     "test" in { } 
  } 
}

2759
2017-10-28 13:52


起源

你能发布导致错误的源代码吗? - kukido
这里问同样的问题: stackoverflow.com/questions/31884182/... - Simon
我在下面的答案中遇到麻烦,最初似乎有用,并找到了我在这里引用的不同解决方案,而不是复制: stackoverflow.com/questions/42368523/...。 - JulienD


答案:


我终于找到了这个解决方案我注入了Guice:

lazy val appBuilder = new GuiceApplicationBuilder()

lazy val injector = appBuilder.injector()

lazy val databaseApi = injector.instanceOf[DBApi] //here is the important line

(你必须导入 play.api.db.DBApi。)

在我的测试中,我只是执行以下操作(实际上我使用其他数据库进行测试):

override def beforeAll() = {
  Evolutions.applyEvolutions(databaseApi.database("default"))
}

override def afterAll() = {
  Evolutions.cleanupEvolutions(databaseApi.database("default"))
}

11
2017-10-28 18:51



使用这种技术,在编写更多测试后,我得到一个“Too many connections”错误: stackoverflow.com/questions/42368523/...。知道泄漏在哪里? - JulienD


考虑到您正在使用Play 2.4,其中演变被移动到一个单独的模块中,您必须添加 evolutions 到您的项目依赖项。

libraryDependencies += evolutions

2
2017-10-28 14:57



evolve已添加到我的build.sbt文件中 - Simon


有权访问 play.api.db.Databases,您必须将jdbc添加到您的依赖项:

libraryDependencies += jdbc

希望它可以帮助一些人来到这里。

编辑:代码将如下所示:

import play.api.db.Databases

val database = Databases(
  driver = "com.mysql.jdbc.Driver",
  url = "jdbc:mysql://localhost/test",
  name = "mydatabase",
  config = Map(
    "user" -> "test",
    "password" -> "secret"
  )
)

您现在拥有了DB的实例,并且可以对其执行查询:

val statement = database.getConnection().createStatement()
val resultSet = statement.executeQuery("some_sql_query")

你可以从中看到更多 文档

编辑:错字


1
2018-06-07 12:46



谢谢,但这不是问题...... - Simon
我猜我的答案还不够完整。当你有这个 play.api.db.Database,您可以像在文档中一样创建数据库对象,然后在那里有数据库实例,然后您可以使用它 Evolutions.applyEvolutions(database) - Jonathan Lecointe
你如何让我的数据库实例与我提供的答案中的方式不同? - Simon
我编辑了我的答案,以提供更多的信息:) - Jonathan Lecointe
代码的问题在于,因为我使用Slick,我可以使用play.api.db.DB获取我的数据库实例 - Simon


我发现使用evolutions运行测试的最简单方法是使用 FakeApplication,并手动输入数据库的连接信息。

def withDB[T](code: => T): T =
  // Create application to run database evolutions
  running(FakeApplication(additionalConfiguration = Map(
    "db.default.driver"   -> "<my-driver-class>",
    "db.default.url"      -> "<my-db-url>",
    "db.default.user"     -> "<my-db>",
    "db.default.password" -> "<my-password>",
    "evolutionplugin"     -> "enabled"
    ))) {
    // Start a db session
    withSession(code)
  }

像这样用它:

"test" in withDB { }

例如,这允许您使用内存数据库来加速单元测试。

您可以访问数据库实例 play.api.db.DB 如果你需要它。你还需要 import play.api.Play.current


0
2017-10-28 15:05



我知道如何启用autoEvolutions,我想要做的是为每个测试文件运行evolution脚本,即使没有更改(在1.sql文件中)。这就是为什么我想拥有一个数据库实例,我不知道我的代码可以在哪里使用它。此外,我已经使用GuiceApplicationBuilder为我的测试设置了不同的配置。 - Simon
为什么不从每个测试的空白DB开始并应用所有演变?否则,如果测试没有将数据库恢复到正确的状态,则会出现问题。 - jazmit
这正是我想要做的! ;)(不是内存数据库,但我不认为它会有所不同。) - Simon
我仍然不明白为什么你需要直接访问数据库实例 - 我使用H2DB并在每次测试后丢弃数据库。但是,它可以作为 play.api.db.DB 一旦FakeApplication运行。 (我知道,可怕的全球状态,游戏开发者正在努力摆脱它) - jazmit
因为我想在真正的PostgreSQL数据库上运行我的测试,特别是因为我使用像postgis和citext这样的扩展。但是和你一样,我希望在每次测试开始时重新启动演变(降低和升级)。 - Simon


使用FakeApplication读取数据库配置并提供数据库实例。

def withDB[T](code: => T): T =
  // Create application to run database evolutions
  running(FakeApplication(additionalConfiguration = Map(
       "evolutionplugin" -> "disabled"))) {
    import play.api.Play.current
    val database = play.api.db.DB
    Evolutions.applyEvolutions(database)
    withSession(code)
    Evolutions.cleanupEvolutions(database)
  }

像这样用它:

"test" in withDB { }

0
2017-10-28 16:10



代码的问题在于,因为我使用Slick,我可以使用play.api.db.DB获取我的数据库实例 - Simon