12
votes

I would like to manually run my evolution script at the beginning of each test file. I'm working with Play! 2.4 and Slick 3.

According to the documentation, the way to go seems to be:

Evolutions.applyEvolutions(database)

but I don't manage to get an instance of my database. In the documentation play.api.db.Databases is imported in order to get a database instance but if I try to import it, I get this error: object Databases is not a member of package play.api.db

How can I get an instance of my database in order to run the evolution script?

Edit: as asked in the comments, here is the entire source code giving the error:

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 { } 
  } 
}
5
Can you post the source code which is causing the error?kukido
The same question is asked here: stackoverflow.com/questions/31884182/…Simon
I had troubles with the answer below that seemed to work at first, and found a different solution that I reference here instead of copying: stackoverflow.com/questions/42368523/….JulienD

5 Answers

11
votes

I finally found this solution. I inject with Guice:

lazy val appBuilder = new GuiceApplicationBuilder()

lazy val injector = appBuilder.injector()

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

(You have to import play.api.db.DBApi.)

And in my tests, I simply do the following (actually I use an other database for my tests):

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

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

Considering that you are using Play 2.4, where evolutions were moved into a separate module, you have to add evolutions to your project dependencies.

libraryDependencies += evolutions
1
votes

To have access to play.api.db.Databases, you must add jdbc to your dependencies :

libraryDependencies += jdbc

Hope it helps some people passing here.

EDIT: the code would then look like this :

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"
  )
)

You now have an instance of the DB, and can execute queries on it :

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

You can see more from the docs

EDIT: typo

0
votes

I find the easiest way to run tests with evolutions applied is to use FakeApplication, and input the connection info for the DB manually.

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)
  }

Use it like this:

"test" in withDB { }

This allows you, for example, to use an in-memory database for speeding up your unit tests.

You can access the DB instance as play.api.db.DB if you need it. You'll also need to import play.api.Play.current.

0
votes

Use FakeApplication to read your DB configuration and provide a DB instance.

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)
  }

Use it like this:

"test" in withDB { }