The marmelab blog

How To Use Docker To Run PHPUnit Tests In Parallel

Published on 4 November 2013 by Emmanuel with tags tdd php docker

Dockers logo

Ahoy sailor !

I've heard you want to know more about all the containers I'm shipping in my boat. Let me tell you the story of Docker, the LinuX Container (LXC) manager that you've dreamt of for a long time.

Docker allows you to run lightweight containers. A container can run any Linux based OS by pulling it from a repository.

The Shipment

Ok now you may think that theses containers are like your well known Virtual Machine, but keep reading young sailor. A container shares his OS core functionnaly with his running host. The copy-on-write mecanism stores only data that differs from his image, hence a container is very lightweight and starts quickly.

An image? Oooh yes, an image is created by a DockerFile that contains a list of instruction telling how to build a container. It's very similar to a VagrantFile: once you've created an image, you can run the container from this image and only the modified data will be stored in the container. This magical behaviour gives the possibility to run hundreds of containers in the same machine.

Like a real container, a Docker's container can be shipped by every Linux OS and can contain anything you need. It will run the same way everywhere.

A Container, For What ?

Now that we know how Docker works, let's make an image that runs a Symfony standard edition and run some tests in parallel.

The treasure to find is a script that retrieves all PHPUnit groups of the application and run them in different containers simultaneously. Consequently, if a test cleans up a database or adds data into a search index, other tests (running in another container) won't be affected because they have they own services.

Let's create a new folder and grab a copy of the last edition of Symfony.

Running On Mac OSX

For now Docker can only run on Linux systems, Mac OSX (based on FreeBSD) does not have a LXC system. This will not frighten a salty dog. We can run a virtual machine thanks to Vagrant to run Docker, so create a file called VagrantFile in your folder:

This file tells to Vagrant to create a virtual machine based on a Ubuntu precise 64bits (Docker can't run on 32 bits), and mounts the current folder to the /vagrant directory of the guest machine.

Start and log to the machine with:

Create The Docker Image

Let's dive into the DockerFile (created in the current folder) :

This file tells Docker to install a Debian Wheezy (7.1), update apt & installs a LAMP environment to run Symfony. You should notice the ADD ./install.sh /install.sh statement, it will copy the install.sh file in the container to setup the application.

The last line defines what should be run directly after booting. Here we run a bash (it's quicker than SSH) and the install.sh script.

What the install.sh looks like:

This script checks if the file parameter.yml exists, otherwise it creates a database and a user, installs the dependencies and configures the application.

One Script to Run Them All

Here is the treasure that you are seeking, the script that runs all your tests. Tet me introduce you to scripts.sh:

First of all, we retrieve all PHPUnit groups by running a container with the phpunit --list-group command.

Next the gnu parallel command helps us to run tests for each group in parallel. Each task is launched by one core of your processor. If you've got a large cruiser with 8 core then you can run 8 tests group simultaneously.

The -v option of Docker mounts the current directory (the /vagrant on the previously create Virtual Machine) to the /app/parallelTests/ folder of the container.

Here is the list of Docker's command if you want to know more about it.

I hope this parchment helps you discover the power of Docker.

Godspeed!

comments powered by Disqus