Testing Your Rails Application with Docker

Development

Reading Time: 4 minutes

In my last article, I showed you how to move a Rails development environment to Docker (and Docker Compose). This time, I want to expand on that and discuss some improvements regarding testing your Rails application.

Running your basic test suite is done quite easily. With the configuration from my last post, you can simply run the following commands to spin up the environment, create and seed the database, and run your test suite.

docker-compose up
docker-compose run -e "RAILS_ENV=test" app rake db:create db:migrate
docker-compose run -e "RAILS_ENV=test" app rake test

This is basically the same way you would run your tests locally and though it might speed up test times a bit (depending on the hardware Docker is running on), it isn’t a huge improvement.

But you could run the tests in multiple containers at the same time.

Running Individual Tests

As with the app running locally, you can run individual test suites by specifying the filename in the run command.

docker-compose run -e "RAILS_ENV=test" app rspec spec/path/to/spec.rb

Running Tests in Parallel Containers

If your Docker host is beefy enough, you could also run your tests in parallel using multiple containers. There are tools like parallel_tests available, which allow you to run your tests in parallel on a single machine; you might want to reuse those as well.

Browser Testing

If you want to run tests via Capybara or a similar tool, you can simply extend your Dockerfile to include the necessary browsers as well as the xfvb package, which provides a virtual display server.

...
# The Firefox package is called Iceweasel on Debian, but still provides the
# `firefox` binary.
RUN \
  DEBIAN_FRONTEND=noninteractive \
  apt-get install -y \
    chromium \
    iceweasel \
    xvfb
...

Include the webdriver in your Gemfile, and you’re good to go. I’d also recommend taking a look at the headless gem, which provides an easy to use wrapper around xvfb and allows you to capture images or video as well.

Alternatively you could switch to using PhantomJS, which provides a headless version of WebKit and doesn’t require any additional packages. Install it by adding the following commands to your Dockerfile.

...
ENV PHANTOMJS_VERSION=1.9.8
RUN \
  cd /usr/local/share && \
  wget https://phantomjs.googlecode.com/files/phantomjs-${PHANTOMJS_VERSION}-linux-i686.tar.bz2 && \
  tar xvf phantomjs-${PHANTOMJS_VERSION}-linux-i686.tar.bz2 && \
  rm phantomjs-${PHANTOMJS_VERSION}-linux-i686.tar.bz2 && \
  ln -s /usr/local/share/phantomjs-${PHANTOMJS_VERSION}-linux-i686/bin/phantomjs /usr/local/bin/phantomjs

Note: We’re using version 1.9.8 of PhantomJS because Linux binaries for version 2 aren’t yet available. If you want to use version 2, you’d need to compile it yourself, but you could then use the above command to download and install it.

Running Development/Test Only Dependencies

If you require dependencies, which should only be running in your test development or environment, you can quite easily add a new container definition in the docker-compose.yml and adapt your configuration accordingly.

For example, Discourse uses Mailcatcher during development. In a traditional setup, you’d be required to install the software on your development computer. However, it becomes even easier with the containerized setup.

Adapt your application definition as detailed below (the development.rb configuration already includes the configuration to send mails via the port defined by Mailcatcher, so you don’t need to change it at all).

app:
  ...
  links:
    ...
    - mailcatcher
...
mailcatcher:
  image: schickling/mailcatcher
  ports:
    - "1080:1080"

Once you restart the environment, you can open the Mailcatcher web interface on the IP of your Docker host and see any mail sent via your application.

Sign up for a free Codeship Account

Docker on Codeship

Like I mentioned in my last post, Codeship is currently preparing a Docker-based CI infrastructure as well. We’ll use Docker Compose (with some extensions) to define your test environment and then have a separate YAML-based configuration for configuring which steps to run.

The platform is still under development, so the available options aren’t set in stone, but the following configuration would run various tests on multiple containers for the Discourse repository.

# codeship-services.yml
app:
  build:
    image: codeship/discourse
    dockerfile_path: Dockerfile
  environment:
    RAILS_ENV: test
  links:
    - postgresql
    - redis
  volumes_from:
    - data
postgresql:
  image: postgres:9.4
redis:
  image: redis:3.0
data:
  image: busybox
  volumes:
    - /data

Combined with the following step definition, we will run your tests in three Docker containers in parallel.

# codeship-steps.yml
- type: parallel
  service: app
  steps:
    - command: bundle exec rspec
    - command: bundle exec rake plugin:spec
    - command: bundle exec rake qunit:test

Head over to Codeship Docker Beta to sign up for the beta.

PS: If you liked this article you might also be interested in one of our free eBooks from our Codeship Resources Library. Download it here: Continuous Integration and Continuous Delivery with Docker

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.



We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.

  • diegotoral

    Great article and good to know CodeShip will be Docker-based!

  • Pingback: Deploying Your Docker Rails App -()

  • Pingback: 2015 年 Ruby 大事件盘点-深圳新媒体门户-一个实用的网站|www.wxshenzhen.cn()

  • Caleb Adam Haye

    Using `run -e “RAILS_ENV=test”` as opposed to exec was very helpful. I only read that first code bit, but it helped a ton. Thanks :)

  • Caleb Adam Haye

    I have to say, I’ve been running my own Jenkins builds for a long time. I just signed up for CircleCI for a new project I’m working on, because their Docker support is free. I love what I see from codeship, but I don’t understand why only plans costing $75 or more will include Docker support. I was just about to try you guys, since I’ve noticed how helpful your articles have been while I set up my docker app, but I’m not ready to pay $75/mo, and by the time I am, I think I’ll probably be comfortable with CircleCI enough to keep using it for free… or upgrade. Anywho, I want to be a customer, but I’m not ready to pay just yet.