【问题标题】:Cannot run tests on h2 in-memory database, rather it runs on PostgreSQL无法在 h2 内存数据库上运行测试,而是在 PostgreSQL 上运行
【发布时间】:2019-02-26 23:02:03
【问题描述】:

(我有多个相关问题,因此我将它们突出显示为粗体)

我有一个play app

  • 播放:2.6.19
  • scala:2.12.6
  • h2: 1.4.197
  • postgresql:42.2.5
  • play-slick/play-slick-evolutions:3.0.1
  • slick-pg: 0.16.3

我正在为 DAO 添加一个测试,我相信它应该在一个 h2 内存数据库上运行,该数据库在测试开始时创建,在测试结束时清除。

但是,我的测试总是在我配置和使用的 PostgreSQL 数据库上运行。

# application.conf
slick.dbs.default.profile="slick.jdbc.PostgresProfile$"
slick.dbs.default.db.driver="org.postgresql.Driver"
slick.dbs.default.db.url="jdbc:postgresql://localhost:5432/postgres"

这是我的测试test/dao/TodoDAOImplSpec.scala

package dao

import play.api.inject.guice.GuiceApplicationBuilder
import play.api.test.{Injecting, PlaySpecification, WithApplication}

class TodoDAOImplSpec extends PlaySpecification {
  val conf = Map(
    "slick.dbs.test.profile" -> "slick.jdbc.H2Profile$",
    "slick.dbs.test.db.driver" -> "org.h2.Driver",
    "slick.dbs.test.db.url" -> "jdbc:h2:mem:test;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE"
  )
  val fakeApp = new GuiceApplicationBuilder().configure(conf).build()
  //val fakeApp = new GuiceApplicationBuilder().configure(inMemoryDatabase()).build()
  //val fakeApp = new GuiceApplicationBuilder().configure(inMemoryDatabase("test")).build()
  "TodoDAO" should {
    "returns current state in local pgsql table" in new WithApplication(fakeApp) with Injecting {
      val todoDao = inject[TodoDAOImpl]
      val result = await(todoDao.index())
      result.size should_== 0
    }
  }
}

对于fakeApp,我尝试了所有三个,但都没有按预期工作 - 我的测试仍然在我的本地 PostgreSQL 表(其中有 3 个待办事项)上运行,因此测试失败。

我尝试过/发现的:

首先,inMemoryDatabase() 只返回一个Map("db.<name>.driver"->"org.h2.Driver", "db.<name>.url"->""jdbc:h2:mem:play-test-xxx"),它看起来与我自己的conf 映射非常相似。但是,有两个主要区别:

  • inMemoryDatabase 使用 db.<name>.xxx 而我的 conf 地图使用 slick.dbs.<name>.db.xxx哪一项应该是正确的?

其次,将conf映射的键重命名为“slick.dbs.default.profile”、“slick.dbs.default.db.driver”和“slick.dbs.default.db.url”会报错。

[error] p.a.d.e.DefaultEvolutionsApi - Unknown data type: "status_enum"; SQL statement:
ALTER TABLE todo ADD COLUMN status status_enum NOT NULL [50004-197] [ERROR:50004, SQLSTATE:HY004]

cannot create an instance for class dao.TodoDAOImplSpec

  caused by @79bg46315: Database 'default' is in an inconsistent state!

这个发现很有趣——它与我使用 PostgreSQL ENUM 类型和slick-pg 有关吗? (见slick-pg issue with h2)。 这是否意味着这是运行 h2 内存测试的正确配置?如果是这样,问题就变成了How to fake PostgreSQL ENUM in h2

第三,我关注this thread,运行sbt '; set javaOptions += "-Dconfig.file=conf/application-test.conf"; test',测试配置文件conf/application-test.conf

include "application.conf"

slick.dbs.default.profile="slick.jdbc.H2Profile$"
slick.dbs.default.db.driver="org.h2.Driver"
slick.dbs.default.db.url="jdbc:h2:mem:test;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE"

毫不奇怪,我得到了与第二次试验相同的错误。

在我看来,第二次和第三次试验指向了正确的方向(将对此进行研究)。 但是为什么我们必须将name 设置为default 还有其他更好的方法吗?

【问题讨论】:

    标签: postgresql playframework h2 play-slick slick-pg


    【解决方案1】:

    默认数据库是default。但是,您可以将其更改为所需的任何其他数据库名称,但是您还需要添加数据库名称。例如,我想要一个具有user 表的comment 数据库:

    CREATE TABLE comment.User(
    id                      int(250)         NOT NULL AUTO_INCREMENT,
    username                varchar(255), 
    comment                 varchar(255), 
    PRIMARY KEY             (id)); 
    

    然后我需要它的配置来连接它(将它添加到application.conf文件中):

    db.comment.url="jdbc:mysql://localhost/comment"
    db.comment.username=admin-username
    db.comment.password="admin-password"
    

    如上所述,您可以使用 test 数据库进行测试,并在测试中使用它。

    本地数据库测试:为什么不像生产环境那样在本地拥有数据库?数据不存在并且在本地运行测试不会触及生产数据库;为什么你需要一个额外的数据库?

    Inconsistent State:这是您编写的 MYSQL 更改数据库中当前数据库的状态时,这可能是基于创建新表或您想要删除它时。

    另外status_enum 显然无法识别为 MySQL 命令。如果不确定,请尝试要在 MySQL 控制台中使用的命令。

    【讨论】:

    • 我使用 PostgreSQL 而不是 MySQL。其余的答案有帮助。我终于转向另一个 PostgreSQL 数据库进行测试。
    • My diff 解决这个问题可能会有所帮助
    猜你喜欢
    • 1970-01-01
    • 2010-10-11
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    • 2020-07-02
    • 2020-12-16
    • 1970-01-01
    相关资源
    最近更新 更多