Docker, a portable, lightweight runtime and packaging tool, is all the rage these days. It’s hard to go to any sort of tech meetup without overhearing people gushing to each other about how cool it is. I’d written some Dockerfiles but wanted to start test driving them. It’s actually fairly straightforward using RSpec and ServerSpec. Here’s how to TDD a Dockerfile that installs Node on Ubuntu.
Start by writing a failing test. This tests that we have Ubuntu 14 installed:
# spec/Dockerfile_spec.rb
require "serverspec"
require "docker"
describe "Dockerfile" do
before(:all) do
image = Docker::Image.build_from_dir('.')
set :os, family: :debian
set :backend, :docker
set :docker_image, image.id
end
it "installs the right version of Ubuntu" do
expect(os_version).to include("Ubuntu 14")
end
def os_version
command("lsb_release -a").stdout
end
end
First we build the Docker image from the Dockerfile in the current directory.
Then we use set
, part of the ServerSpec DSL, for telling it how to connect to
the host we are testing. We then test that the results of the command
lsb_release -a
includes “Ubuntu 14”. I’ve pulled it out into its own method
for clarity.
Now let’s run our test and watch it fail:
$ rspec spec/Dockerfile_spec.rb
...
Cannot build a directory without a Dockerfile (Docker::Error::ServerError)
...
Add a Dockerfile:
FROM ubuntu:14.04
MAINTAINER Mason Fischer <mason@thoughtbot.com>
And watch it pass:
$ rspec spec/Dockerfile_spec.rb
1 example, 0 failures
Testing package installation
We can also test that packages are installed. For example, let’s add a test that Node is installed:
# spec/Dockerfile_spec.rb
require "serverspec"
require "docker"
describe "Dockerfile" do
before(:all) do
image = Docker::Image.build_from_dir('.')
set :os, family: :debian
set :backend, :docker
set :docker_image, image.id
end
it "installs the right version of Ubuntu" do
expect(os_version).to include("Ubuntu 14")
end
# This test is new
it "installs required packages" do
expect(package("nodejs")).to be_installed
end
def os_version
command("lsb_release -a").stdout
end
end
Again we can watch our test fail:
$ rspec spec/Dockerfile_spec.rb
...
1) Dockerfile installs required packages
Failure/Error: expect(package("nodejs")).to be_installed
expected Package "nodejs" to be installed
...
Let’s add the following line to the end of our Dockerfile:
RUN apt-get update && apt-get install -y nodejs
And watch the test pass.
$ rspec spec/Dockerfile_spec.rb
2 examples, 0 failures
ServerSpec can test more than just packages. You can test commands, ports, services and pretty much anything you can dream up.
Thanks to Taichi Nakashima and Pieter Joost Van de Sande for their posts on TDDing Dockerfiles which is where I got a lot of this information.
The example Dockerfile and Dockerfile_spec.rb are posted in this Gist.