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 <eshlox@docker.is.very.cool>
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \ echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \ apt-get update && \ apt-get install -y \ python3-dev \ python3-pip \ xvfb \ google-chrome-stable \ chromedriver
ENV PATH /usr/lib/chromium/:$PATH
ADD requirements.txt /root/requirements.txtRUN 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"services: behave: network_mode: "host" shm_size: 256m environment: - DISPLAY=$DISPLAY - CHROME_BINARY_PATH=/usr/bin/google-chrome - DBUS_SESSION_BUS_ADDRESS=/dev/null volumes: - .:/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 shm_size to set size of /dev/shm and DBUS_SESSION_BUS_ADDRESS 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. CHROME_BINARY_PATH 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 CHROME_BINARY_PATH and how to run Chrome. As you can see the CHROME_BINARY_PATH 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 webdriverfrom selenium.webdriver.chrome.options import Options
CHROME_BINARY_PATH = os.environ.get('CHROME_BINARY_PATH')
chrome_options = Options()if CHROME_BINARY_PATH: chrome_options.binary_location = CHROME_BINARY_PATHchrome_options.add_argument('--no-sandbox')chrome_options.add_argument('--disable-setuid-sandbox')browser = webdriver.Chrome(chrome_options=chrome_options)
Here is a small part of docker.sh script to simplify running tests.
#!/usr/bin/env bash
case "$1" in background) docker-compose run --rm behave behave -D $2 -D xvfb ;; chrome) xhost +si:localuser:root docker-compose run --rm behave behave -D $2 xhost -si:localuser:root ;; behave) xhost +si:localuser:root docker-compose run --rm behave behave "${@:2}" xhost -si:localuser:root ;; pdb) xhost +si:localuser:root docker-compose run --rm --service-ports behave behave --no-capture "${@:2}" xhost -si:localuser:root ;;esac
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.