To have a database available in scalatest with evolutions I use this extension of the default PlaySpec
inspired by this SO question:
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()
}
}
It applies database evolutions when the suite starts, and reverts them when the suite ends. A test then looks like
class ProjectsSpec extends ResetDbSpec with OneAppPerSuite { ...
After adding more tests like this, I hit a point where some tests that succeed when I run them alone, fail with this error:
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
As can be see in the code above, I tried to add the line
databaseApi.database("default").shutdown()
in afterAll()
to mitigate that, but it had no effect. I tried to not run tests in parallel, but no effect either. Where is it that I open db connections without closing them, and where should I call shutdown()
?
N.B. I use Play 2.5.10 and Slick 3.1.
I have a lot of tests (about 500) and I don't get this error, the only difference I have with your code is that I add
databaseApi.database("default").getConnection().close()
and
Play.stop(fakeApplication)
for the integration tests.
Let me know if it changes anything.
Although it does not answer to what is happening with the connections leakage, I finally managed to hack around this:
Add jdbc to you libraryDependencies, even if the Play-Slick FAQ tells you not to do it:
# build.sbt libraryDependencies += jdbc
Restart sbt to take changes into account. In IntelliJ, you will want to refresh the project, too.
Disable the jdbc module that is conflicting with play-slick (credits: this SO answer):
# application.conf play.modules.disabled += "play.api.db.DBModule"
At the same place you should have already configured something like
slick { dbs { default { driver = "slick.driver.MySQLDriver$" db.driver = "com.mysql.jdbc.Driver" db.url = "jdbc:mysql://localhost/test" db.user = "sa" db.password = "" } } }
Now you can use
play.api.db.Databases
from jdbc and its methodwithDatabase
to run the evolutions.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) } } }
Finally, call tests requiring a db reset like this:
class MySpec extends ResetDbSpec {...}
Of course it sucks repeating this config both in "application.test.conf" and in withDatabase()
, plus it mixes two different APIs, not talking about performance. Also it adds this before and after each suite, which is annoying:
[info] application - Creating Pool for datasource 'default'
[info] application - Shutting down connection pool.
If somebody has a better suggestion, please improve on this answer! I have been struggling for months.
来源:https://stackoverflow.com/questions/42368523/play-tests-with-database-too-many-connections