-->

How to apply manually evolutions in tests with Sli

2019-04-05 05:12发布

问题:

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

回答1:

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:

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
  • Source: Evolutions
  • Relevant commit: Split play-jdbc into three different modules


回答3:

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



回答4:

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.



回答5:

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