Dockerize Behave (Selenium) tests

November 22, 2016 - IT

I like to have everything in a Docker containers. Recently we've added Behave tests to the project where I'm currently working. My assumptions for Docker container with tests:

  • we should be able to run tests in the background (xvfb)
  • we should be able to run tests using Chrome browser
  • we should be able to use pdb
  • we should be able to run tests on application from other container (example: http://localhost:8080 on host)
  • we should be able to use simple commands (shortcuts) instead of long docker/docker-compose commands

Let's start with Dockerfile.

FROM python:3.5

MAINTAINER Przemysław Kołodziejczyk <[email protected]>

RUN wget -q -O - | apt-key add - && \
    echo "deb [arch=amd64] stable main" > /etc/apt/sources.list.d/google.list && \
    apt-get update && \
    apt-get install -y \
        python3-dev \
        python3-pip \
        xvfb \
        google-chrome-stable \

ENV PATH /usr/lib/chromium/:$PATH

ADD requirements.txt /root/requirements.txt
RUN pip3 install -r /root/requirements.txt

It's a very simple Docker file. We will use Docker image with Python 3.5. During the build process Docker will install Chrome browser and all additional packages. We also need to add an additional path to system PATH to specify where the chromedriver is installed.

Now is the time for docker-compose.yml file.

version: '2'
    network_mode: "host"
    shm_size: 256m
      - CHROME_BINARY_PATH=/usr/bin/google-chrome
      - DBUS_SESSION_BUS_ADDRESS=/dev/null
      - .:/behave
      - /tmp/.X11-unix:/tmp/.X11-unix
    working_dir: /behave

What's going on here. Network mode set to host means that our tests will be able to access localhost from host so basically it will be possible to run tests for example on http://localhost:8080. We need shmsize to set size of /dev/shm and DBUSSESSIONBUSADDRESS set to /dev/null, without that I had a lot of issues with running Chrome. We need to pass $DISPLAY environment variable and mount /tmp/.X11-unix to be able to run GUI browser from container. CHROMEBINARYPATH is just a path to Chrome browser, I'm using it to set Chrome location in chromedriver and use Chrome instead of Chromium. (Without that chromedriver uses Chromium as default option.)

It's mostly everything what is related to the Docker. Below there is only a part of tests to show how to use CHROMEBINARYPATH and how to run Chrome. As you can see the CHROMEBINARYPATH is set only when it exists in environment. Not everyone is using Docker and in this way when someone runs tests without Docker and without that variable, the tests will use browser from user system (Chromium or Chrome).

from selenium import webdriver
from import Options


chrome_options = Options()
    chrome_options.binary_location = CHROME_BINARY_PATH
browser = webdriver.Chrome(chrome_options=chrome_options)

Here is a small part of script to simplify running tests.

#!/usr/bin/env bash

case "$1" in
        docker-compose run --rm behave behave -D $2 -D xvfb
        xhost +si:localuser:root
        docker-compose run --rm behave behave -D $2
        xhost -si:localuser:root
        xhost +si:localuser:root
        docker-compose run --rm behave behave "${@:2}"
        xhost -si:localuser:root
        xhost +si:localuser:root
        docker-compose run --rm --service-ports behave behave --no-capture "${@:2}"
        xhost -si:localuser:root

As a $2 parameter we are passing the environment name or URL where the tests should be run, example: local, staging, http://localhost:8080. Most of that commands are used to run behave in container. Just remember that if you want to use pdb to debug tests then you need to add --service-ports parameter. As you can see there is also a xhost command. This command allows root user (from Docker container) to access the running X server (from host) and using this we can display Chrome GUI from container.