使用数据库进行测试:“连接太多”

时间:2017-02-21 13:23:40

标签: scala testing playframework playframework-2.5 play-slick

为了让scalatest中的数据库具有evolutions,我使用this SO question启发的默认PlaySpec扩展名:

trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll {
  lazy val appBuilder = new GuiceApplicationBuilder()
  lazy val injector = appBuilder.injector()
  lazy val databaseApi = injector.instanceOf[DBApi]

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

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

它在套件启动时应用数据库演变,并在套件结束时恢复它们。然后测试看起来像

class ProjectsSpec extends ResetDbSpec with OneAppPerSuite { ...

在添加了更多这样的测试之后,我遇到了一些问题,当我单独运行它们时,某些测试会成功,但是会出现此错误:

  

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:数据源拒绝建立连接,来自服务器的消息:“连接太多”

从上面的代码中可以看出,我尝试添加行

databaseApi.database("default").shutdown()
afterAll()中的

可以减轻这种影响,但它没有效果。我试图不并行运行测试,但也没有效果。我在哪里打开数据库连接而不关闭它们,我应该在哪里调用shutdown()

N.B。我使用Play 2.5.10和Slick 3.1。

1 个答案:

答案 0 :(得分:1)

虽然它没有回应连接泄漏的情况,但我终于成功解决了这个问题:

  1. jdbc 添加到libraryDependencies,即使Play-Slick FAQ告诉您不要这样做:

    # build.sbt
    libraryDependencies += jdbc
    

    重新启动sbt以考虑更改。在IntelliJ中,您也需要刷新项目。

  2. 禁用与play-slick冲突的 jdbc 模块(credit:this SO answer):

    # application.conf
    play.modules.disabled += "play.api.db.DBModule"
    

    在同一个地方你应该已经配置了像

    这样的东西
    slick {
      dbs {
        default {
          driver = "slick.driver.MySQLDriver$"
          db.driver = "com.mysql.jdbc.Driver"
          db.url = "jdbc:mysql://localhost/test"
          db.user = "sa"
          db.password = ""
        }
      }
    }
    
  3. 现在,您可以使用 jdbc 中的play.api.db.Databases及其方法withDatabase来运行演变。

    import org.scalatest.BeforeAndAfterAll
    import org.scalatestplus.play.PlaySpec
    import play.api.db.{Database, Databases}
    import play.api.db.evolutions.Evolutions
    
    
    trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll {
    
      /**
       * Here we use Databases.withDatabase to run evolutions without leaking connections.
       * It slows down the tests considerably, though.
       */
    
      private def withTestDatabase[T](block: Database => T) = {
        Databases.withDatabase(
          driver = "com.mysql.jdbc.Driver",
          url = "jdbc:mysql://localhost/test",
          name = "default",
          config = Map(
            "username" -> "sa",
            "password" -> ""
          )
        )(block)
      }
    
      override def beforeAll() = {
        withTestDatabase { database =>
          Evolutions.applyEvolutions(database)
        }
      }
    
      override def afterAll() = {
        withTestDatabase { database =>
          Evolutions.cleanupEvolutions(database)
        }
      }
    
    }
    
  4. 最后,调用需要db重置的测试,如下所示:

    class MySpec extends ResetDbSpec {...}
    
  5. 当然,在" application.test.conf"中都很难重复这个配置。在withDatabase()中,加上它混合了两种不同的API,而不是性能。此外,它在每个套件之前和之后添加了这个,这很烦人:

      

    [info] application - 为数据源创建池'默认'
      [info] application - 关闭连接池。

    如果有人有更好的建议,请改进这个答案!我已经挣扎了几个月。