Integration testing using docker and scala
A few weeks ago I published a post on Reddit where I tried to advertise my lib - testcontainers-scala. This failed, I got no feedback at all. This prompted me to write this post and show how awesome integration testing might be.
Here I’m going to show a simple example of selenium tests. Let’s get it started.
Testcontainers
Testcontainers-scala is a wrapper for testcontainers-java that allows using docker containers for functional/integration testing.
TestContainers is a Java 8 library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
Assumptions
You know how to use SBTYou’re able to copy and paste dependencies to yourbuild.sbt
- You use scala 2.11
- You run all of these on java >8
- You have docker installed on your machine
If all of those points are true then we’re ready to write some code.
Build script
I’m not going to make it complex, so here’s the simplest minimalistic build.sbt
that we need to start. It’s enough for showing the power of testcontainers.
This is pretty standard build script, so there’s no problem just to copy and paste this into build.sbt
of your existing project.
Important note
The version of selenium-java links to a version of selenium/standalone-chrome-debug container. If you are using a version different from 2.53.0 please check a version of the container manually. See the official docker hub pageSpecs
Now we can write some specs. Since I have no prepared backend, I’m going to write specs in terms of scalatest which test reddit.com.
This is all you need to test your GUI inside the docker. Now let’s break it down. We have SeleniumTestContainerSuite
trait that does all the magic under the hood. It starts a clean new container on each test case, so you don’t need to worry about the state - no data shared between test cases. To make it work in a basic scenario you just need to configure DesiredCapabilities
(1) - here it’s chrome, but you can use firefox as well.
There are three test cases (3-5). The first two (3-4) are regular selenium tests wrapped with nice scalatest DSL.
And the last one is a test that sometimes fails. But you can say that there is no way to figure out what is going on inside the container and this may be true, but not in our case. As you see in (3) we ask testcontainers to record all failed tests and produce .flv
file. This is how it looks like:
The tests case checks that after clicking on a first link in the list a user won’t be redirected to a foreign domain, in fact, he will.
Conclusion
I had a lot of problems with old fashioned approaches like Chrome/Firefox/Remote/etc. drivers running them locally and on CI servers, and I had a tough time with modern approaches like phantom.js. This seems much more reliable and convenient because:
- Tests are reproducible: if it fails on CI server it fails on your dev environment and visa verse.
- Each test case is stateless: you don’t need to worry about cleaning cookies, local storage, etc. Each test works with its own clean browser.
- Easy to start in parallel: since there’s no state, you can run it in parallel.
- Simple troubleshooting: if a test fails you can watch recorded video or fallback to local Chrome/Firefox drivers.
It’s free and open-sourced - github project with all instructions. Your contributions are very welcome.