Use Docker to configure, compile, and test.

Background

The provided Dockerfiles will build two Docker images:

  • CMake and gcc
  • CMake, gcc, and CppUTest

These can be used to easily compile both production and test code.

The source and build directories are bind-mounted to the container. This allows source code changes to be made on the host and easily compiled in the container. It also allows the build results that are generated by the container to persist after the container is stopped.

Prerequisites

  • Docker v17.05+

Setup

Before you can run a Docker container, you need a Docker image. Either pull an image from DockerHub or build your own.

Pull Docker Image

Pull a pre-built image from DockerHub:

$ docker pull kevinwmatthews/gcc-cmake:8-3.13.1
$ docker pull kevinwmatthews/cpputest-gcc-cmake:v3.8-2b45d38

I like to tag each image with a name that is easy to remember:

$ docker tag kevinwmatthews/gcc-cmake:8-3.13.1 cmake
$ docker tag kevinwmatthews/cpputest-gcc-cmake:v3.8-2b45d38 cpputest

Build Docker Image

The syntax for building a Docker image is:

# docker build --tag <image_name> <relative/path/dir/with/Dockerfile/>

Specify the directory that contains the Dockerfile, not the Dockerfile itself.

I prefer to tag the image very specifically in order to track changes and then generate a user-friendly tag for use at the command line:

$ docker build --tag gcc-cmake:8-3.13.1 Dockerfiles/cmake/
$ docker tag gcc-cmake:8-3.13.1 cmake
$ docker build --tag cpputest:v3.8-2b45d38 Dockerfiles/cpputest/
$ docker tag cpputest:v3.8-2b45d38 cpputest

Run Docker Container

A docker image can be run simply using docker run <image_name>, but we want to customize several aspects of this container. In particular, we want to be able to run both test and production builds.

This repo features two example .env files, one for production and one for testing:

  • test.env.example
  • production.env.example

Copy and edit each to be appropriate to your system.

The generic command for starting a container is:

# ENV_FILE=<env_file> ./docker_run.sh <image_name>

Test Build

Create a .env file for testing:

$ cp test.env.example test.env

Edit this file to be appropriate to your system. Note that Docker requires absolute paths.

Run the container with:

$ ENV_FILE=test.env ./docker_run.sh cpputest

Once inside the container, configure using:

$ cmake ../cpputest_intro

This project will compile unit tests by default.

Compile with:

$ make

CMake will run all test suites with:

$ ctest
# or
$ make test

To run individual test executables, run:

# ./bin/<test_executable>
$ ./bin/test_cpputest_intro

I prefer to colorize the tests’ output with:

$ ./bin/test_cpputest_intro -c

When finished, stop the container using:

$ exit

Production Build

It is important to distinguish between test and production builds. Unit tests often override behavior of production code with mocks, custom functions, and memory leak checks. This configuration uses a separate build directory for production builds to ensure that test code is kept separate.

Create a .env file for production:

$ cp production.env.example production.env

Edit this file to be appropriate to your system. Note that Docker requires absolute paths.

Run the container with:

$ ENV_FILE=production.env ./docker_run.sh cmake

You can also build with the cpputest image, but using the cmake image guarantees that no test code can accidentally be shipped.

Once inside the container, configure using:

$ cmake ../cpputest_intro -DCOMPILE_TESTS=OFF

Note that unit tests are explicitly disabled.

Compile with:

$ make

This project illustrates unit testing on a library so there are no production executables to run.

When finished, stop the container using:

$ exit