---
title: Test Drive Your Dockerfiles with RSpec and ServerSpec
teaser: Learn to TDD your Dockerfiles with RSpec and ServerSpec.
tags: docker,tdd,testing,unix
author: Mason Fischer
published_on: 2015-02-17
---

[Docker](https://www.docker.com/whatisdocker/), 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](http://rspec.info/) and
[ServerSpec](http://serverspec.org/).  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:

```ruby
# 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:

```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:

```ruby
# 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:

```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](http://serverspec.org/resource_types.html#command),
[ports](http://serverspec.org/resource_types.html#port),
[services](http://serverspec.org/resource_types.html#service) and pretty much
anything you can [dream up](http://serverspec.org/resource_types.html).

Thanks to [Taichi Nakashima](https://coderwall.com/p/5xylsg/tdd-for-dockerfile-by-rspec-severspec) and
[Pieter Joost Van de Sande](http://blog.wercker.com/2013/12/23/Test-driven-development-for-docker.html) 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](https://gist.github.com/masonforest/194e0cb6bb16c88e21a0).
