Unit test in Play! Framework with Slick

Published 2014-07-12 on Farid Zakaria's Blog

Testing

The play framework includes some pretty good integration/documentation on how to perform testing however most of it relies on requiring a Play! application to be created (i.e. FakeApplication) and the fact that they share the same database. The second point was the more troublesome one, since in ScalaTest the tests are run in parallel. The following is what I have done to get around these problems.

trait DatabaseInitializationPerTest extends PlaySpec with BeforeAndAfter {
//create a unique database name, which is the class that implements this trat
val dbName = this.toString.toLowerCase()

//the postgres database is always available. Connect to it and drop the current 
//test database (i.e. classname)
// Drop and create the database
val postgres = Database.forURL(s"jdbc:postgresql://localhost/postgres", driver = "org.postgresql.Driver")
  postgres withSession {
    implicit dbServerSession =>
      {
        logger.debug(s"Creating database: $dbName")
        Q.updateNA(s"DROP DATABASE IF EXISTS $dbName; CREATE DATABASE $dbName;").execute
      }
  }

// Connect to the database
implicit lazy val database = Database.forURL(s"jdbc:postgresql://localhost/$dbName", driver = "org.postgresql.Driver");

  before {
    database withSession { implicit session =>
      logger.debug(s"Creating the database: $dbName")
      val evolution_seq = play.api.db.evolutions.Evolutions.applicationEvolutions(new java.io.File("."), this.getClass().getClassLoader(), "default")
      evolution_seq.flatMap(e => EvolutionSqlScript(e.sql_up).statements).foreach{ sql =>
        Q.updateNA(sql).execute
      }
    }
  }

  after {
    database withSession { implicit session =>
      logger.debug(s"Destroying the database: $dbName")
      val evolution_seq = play.api.db.evolutions.Evolutions.applicationEvolutions(new java.io.File("."), this.getClass().getClassLoader(), "default")
      //I believe you have to apply sql_down in the reverse order
      evolution_seq.reverse.flatMap(e => EvolutionSqlScript(e.sql_down).statements).foreach{ sql =>
        Q.updateNA(sql).execute
      }
    }
  }

  /*
   * The following class was taken from the Play framework however they listed theirs as private.
   * @href https://github.com/playframework/playframework/blob/master/framework/src/play-jdbc/src/main/scala/play/api/db/evolutions/Evolutions.scala
   */
  case class EvolutionSqlScript(sql: String) {
    def statements: Seq[String] = {
      // Regex matches on semicolons that neither precede nor follow other semicolons
      sql.split("(?<!;);(?!;)").map(_.trim.replace(";;", ";")).filter(_ != "")
    }
  }

}

The above code makes re-use of the Evolution plugin provided by Play! The code creates Evolution objects (which contain UpSQL and DownSQL statements) and we can apply them on a before / after method before each test.