I've never been 100% happy with the way I test Play applications. I've settled on an approach that I've been using for a while but it feels a bit hacky and that I'm missing something simple.
I use SQLite and have a single database configuration called default
that I override in my test conf file:
application.conf
slick.dbs.default {
profile = "slick.jdbc.SQLiteProfile$"
db.driver = "org.sqlite.JDBC"
db.url = "jdbc:sqlite:defaultDB.sqlite"
}
application.test.conf
include "application.conf"
play = {
evolutions.enabled = false
}
slick.dbs.default {
profile = "slick.jdbc.SQLiteProfile$"
db.driver = "org.sqlite.JDBC"
db.url = "jdbc:sqlite:memory;DB_CLOSE_DELAY=-1"
}
As you can see from my test configuration I like using an in-memory database for testing. I like using in-memory db's for testing for a few reasons
- I find it easier to manage test data in SQL files
- The database is automatically dumped after the tests have finished
- It's easy to move to another dev machine
I have 2 sets of evolution scripts. One for the dev/prod database stored under evolutions/default/<n>.sql
and another set for the test database stored under evolutions/test/<n>.sql
.
In my tests I use the Injecting
trait to inject the database into the test suite and run the test
evolutions, like this:
[TestName]Spec.scala
class MySpec extends PlaySpec with BeforeAndAfterAll with GuiceOneAppPerSuite with Injecting {
import ThisClassLoaderEvolutionsReader.evolutions
override def beforeAll(): Unit = {
super.beforeAll()
val db = inject[DBApi].database("default")
Evolutions.applyEvolutions(db, SimpleEvolutionsReader.forDefault(evolutions("test") :_*))
}
override def afterAll(): Unit = {
super.afterAll()
val db = inject[DBApi].database("default")
Evolutions.cleanupEvolutions(db)
}
"My Test" should {
"do something useful" in {
...
}
}
}
Things I don't like about this approach:
- I store my test data in evolution scripts, it works quite well but it seems wrong.
- I need to maintain 2 sets of evolution scripts.
- In order to run tests I need an Application so that I can inject the database. That seems too "heavy".
Does my approach seem sensible? Is there a generally agreed upon method for handling tests in Play?