Hi all, back again with the second part of the play scala+slick+postgres adventure.
In part 1, I touched on some of the hurdles I needed to overcome in order to get things up and running (UPDATE:. the docs have been updated, and Mirco has done a really good job of making this more clear: https://www.playframework.com/documentation/2.4.0/PlaySlick). In this article, I'd like to show you how to set up a quick and snappy testing environment.
For starters, we will want a separate test database for postgres. For local tests, just manually create the database and user, and grant that user privileges to create tables, etc. on that database:
Yes, I know, you don't need 3 psql calls to do this but it works and I'm extremely lazy.
Now, let's start looking at the bigger picture. What if we wanted to set up continuous integration so we could have our tests run every time we git push'd? That sounds good, so let's do that with Travis CI. I'll leave it up to you to get your repository and account set up. Once that's done, check out the next part.
Travis CI makes setting up CI testing with all sorts of things really easy. Basically, you just create a file named ".travis.yml" with your configuration options, add it to your repo (I've only done this with github, I don't know how other git hosts work with Travis) and it takes care of the rest after you commit it and push. Here's the one we're going to be working off of:
Very simply, we tell Travis we're using scala, java 8, specifying a shell script which will kick off our tests (source shown below), and that we want to use postgres and have it run the commands in before_script prior to running our tests. Here's the script that runs our tests:
Briefly, this checks for an environment variable called
STEEL_TEST_LOCAL being set to 1, which, if present, tells us we should nuke the current test tables so we can start clean for this upcoming test run. Set this on your local environment so you have fresh and clean test tables prior to each test run. Travis doesn't care about this since it tears everything down automatically at the end of the test.
The next line uses a tool called Flyway to migrate our database changes. I actually really like Flyway, thusfar at least, because it was extremely easy to set up and start using. It completely blows Play's evolutions out of the water. Let's set that up really quick.
Add the Flyway dependencies and configuration to your build.sbt, like so:
The one thing here that needs explaining is the flywayLocations key. To specify a path on the filesystem (local to where your tests are being run out of, so most likely your app root), you pass something like
So, we have flyway set up for migrations, the next step is to create some migrations and have them applied. Flyway actually has excellent and extremely simple documentation on how to do this, and since we're using sbt to manage our tests, here's the introduction to do so: http://flywaydb.org/getstarted/firststeps/sbt.html.
Backing up slightly, I want to explain one more line in the build.sbt file:
javaOptions in Test ++= Seq("-Dconfig.file=conf/test.conf")
This is all you need to specify a different configuration file for your test environment. This is really useful because you can just copy conf/application.conf, and change the database credentials to match your test environment, and it will automatically be picked up when your tests run (example here: https://github.com/dhoss/steel/blob/207ce910e668457c3870446322d98e94f5271f88/conf/test.conf#L40)
So, back to setting up our CI environment. In our run_tests.sh script, we:
- check if we are running locally, and if so, nuke the test database
- otherwise, we run our migrations with flyway + sbt, and because flyway lets us do so, we override the default database configuration parameters and set them to our test's parameters.
- lastly, we finally call sbt to run ours tests with
That's pretty much it. I found it very simple to get a small, no-nonsense, test environment set up that transfers over quite nicely to a relatively robust CI solution.
Next time, I'm planning on discussing some more application specific things dealing with getting your queries right with slick under this set up.