使用Slick,specs2和Postgresql进行2.4测试

时间:2015-07-02 23:26:17

标签: postgresql scala specs2 playframework-2.4 slick-3.0

我想要的是使用相同的数据库引擎,与生产中相同的演变和配置来运行我的测试。我的db是PostgreSQL 9.4,我使用Slick 3.0.0来访问它。

这里有问题:

  • 在并行测试执行的情况下,我在同一个数据库上同时运行了几个进化。这会导致错误。
  • 在顺序测试执行的情况下,线程池有另一个错误。

这里有详细信息。

我使用evolutions为每个测试初始化​​db。为此,我准备了一个基本规范类:

 class DatabaseSpecification extends PlaySpecification {
  protected val defaultAppBuilder =
    new GuiceApplicationBuilder()
      .configure(ConfigurationLoader.loadFirst("application.test.override.conf", "application.test.conf"))

  protected def afterEach(app: Application) = {
    recreateDbSchema(app)
  }

  private def recreateDbSchema(app: Application) = {
    val dbConfig = DatabaseConfigProvider.get[JdbcProfile](app)
    import dbConfig.driver.api._

    val recreateSchema: DBIO[Unit] = DBIO.seq(
      sqlu"drop schema public cascade",
      sqlu"create schema public"
    )    
    Await.ready(dbConfig.db.run(recreateSchema), 5 seconds)
  }

  abstract class DatabaseContext() extends WithApplication(defaultAppBuilder.build()) {
    protected val injector = implicitApp.injector

    override def around[T](t: => T)(implicit evidence$2: AsResult[T]): Result = super.around {
      try {
        t
      } finally {
        afterEach(implicitApp)
      }
    }
  }

}

其中application.test.override.conf是测试的配置文件。

在祖先规范中还有几个测试:

"save1 and query" in new DatabaseContext {
  // create new user
  val accountRepo = injector.instanceOf[SystemUserRepo]
  val user = new SystemUser(id = 0, login = "admin", passwordHash = "", role = Role.Administrator)
  val futureUserId = accountRepo.create(user)

  // check if user id is greater then zero
  val userId = await(futureUserId)(5 second)
  userId must be_>(0)
}

"second one1" in new DatabaseContext {
  1 mustEqual 1
}

如果我并行运行整个规范的测试(默认),那么在其中一个测试中获得异常Database 'default' is in an inconsistent state![An evolution has not been applied properly. Please check the problem and resolve it manually before marking it as resolved.] @6mk338l87: Database 'default' is in an inconsistent state!

如果我按顺序运行class AccountRepositoryTest extends DatabaseSpecification { sequential ... }另一个例外

Task slick.backend.DatabaseComponent$DatabaseDef$$anon$2@2744dcae rejected from java.util.concurrent.ThreadPoolExecutor@16d0e521[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 3]
java.util.concurrent.RejectedExecutionException: Task slick.backend.DatabaseComponent$DatabaseDef$$anon$2@2744dcae rejected from java.util.concurrent.ThreadPoolExecutor@16d0e521[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 3]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
    at scala.concurrent.impl.ExecutionContextImpl$$anon$1.execute(ExecutionContextImpl.scala:136)
    at slick.backend.DatabaseComponent$DatabaseDef$class.runSynchronousDatabaseAction(DatabaseComponent.scala:224)
    at slick.jdbc.JdbcBackend$DatabaseDef.runSynchronousDatabaseAction(JdbcBackend.scala:38)
    at slick.backend.DatabaseComponent$DatabaseDef$class.runInContext(DatabaseComponent.scala:201)
    at slick.jdbc.JdbcBackend$DatabaseDef.runInContext(JdbcBackend.scala:38)
    at slick.backend.DatabaseComponent$DatabaseDef$class.runInternal(DatabaseComponent.scala:75)
    at slick.jdbc.JdbcBackend$DatabaseDef.runInternal(JdbcBackend.scala:38)
    at slick.backend.DatabaseComponent$DatabaseDef$class.run(DatabaseComponent.scala:72)
    at slick.jdbc.JdbcBackend$DatabaseDef.run(JdbcBackend.scala:38)
    at repository.GenericCRUD$class.create(GenericCRUD.scala:50)
    at repository.GenericCRUDImpl.create(GenericCRUD.scala:70)
    at unit.repositories.AccountRepositoryTest$$anonfun$3$$anon$1.delayedEndpoint$unit$repositories$AccountRepositoryTest$$anonfun$3$$anon$1$1(AccountRepositoryTest.scala:39)
    at unit.repositories.AccountRepositoryTest$$anonfun$3$$anon$1$delayedInit$body.apply(AccountRepositoryTest.scala:35)

它发生在val futureUserId = accountRepo.create(user)行。可悲的是,我不知道为什么第二个例外会抛出。顺便说一下,我当然喜欢并行进行测试,但不知道如何实现它。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

目前您应该使用sequential运行数据库测试,否则它将失败。 线程池错误来自:

protected val defaultAppBuilder =
    new GuiceApplicationBuilder()
      .configure(ConfigurationLoader.loadFirst("application.test.override.conf", "application.test.conf"))

它应该是一个功能:

protected def defaultAppBuilder =
    new GuiceApplicationBuilder()
      .configure(ConfigurationLoader.loadFirst("application.test.override.conf", "application.test.conf"))

然后它将开始工作。我们这样做,但是我们有抽象类,其中val application我们可以配置东西,而def app只会执行def app = application.build(),这样我们仍然可以扩展GuiceApplictionBuilder。 / p>

目前我首先遇到了同样的错误,你绝对不希望每次测试都重复使用相同的应用程序。

所以试试吧,你有一个非常好的功能测试套件用于播放应用程序。

然而,我们唯一不做的是public drop schema我们依靠进化来解决这个问题。如果他们错了,我们会立即看到错误。