April 27, 2020

Selenium + Docker: How to Run Selenium Tests in Docker

Open Source Automation

By running Selenium tests through Docker containers, you can save time when creating your tests and get more testing options.

This blog post will provide an overview of how to run Selenium tests in Docker. All scripts can also be found on GitHub.

Table of Contents:

What is Docker?

Docker is a software containerization platform that provides virtualization from the operating system level. In Docker, all software parts can be organized in containers. This includes the operating system, software, dependencies, environment variables, etc.

Containers can be shared among different users, enabling quick installation and running of software and services. This makes Docker handy for automation testing, as the relevant container can just be downloaded and run as part of the automated test. However, Docker is also secure because it runs as an isolated process on the host machine. Docker can be run on any computer on any infrastructure as well as in the cloud, including Linux, Windows, Mac, Amazon, Azure, and more.

Docker Benefits

  • Docker is open source. This means that you can find many images (used to generate containers) and use them. However, this also means that there is no official Docker support.
  • Docker can be an integral part of Continuous Deployment and Continuous Testing, by ensuring you have a consistent environment when developing and going into production. This is because configurations and dependencies are maintained internally, and will not change.
  • Docker is isolated, secure, and portable. However, it requires expertise as there is no GUI and it does not run at bare metal speed.

Why Test With Selenium & Docker Together?

When it comes to automated testing, teams often find using Docker containers advantageous for creating test environments with varied configurations and taking them down once the tests finish running.

For Selenium testing, Docker containers can also help in two critical ways: cross-browser testing and parallel testing. 

Cross-Browser Testing

Cross-browser testing enables teams to check whether your application works effectively when people access it through different browser-OS combinations. With all the different browser-OS combinations available today, it becomes challenging to set up relevant test environments for all of them.

By using Docker containers, teams can set up test environments on the go and bring them down once the tests are done.

Parallel Testing

Parallel testing is yet another important application of Docker containers in Selenium testing. Compared to running tests sequentially, running tests in parallel saves time and gives teams faster feedback. Yet, parallel testing requires a lot of infrastructure to be set up, which directly impacts the cost of testing effectively.

With Docker containers, teams can run multiple containers on a single server. Teams can get the maximum use of the underlying hardware while also achieving parallel testing at reasonable costs.

How To Run Selenium Tests in Docker

Before running Selenium tests in Docker containers, we need to install and set up Docker properly. The pre-requisite step to run a Selenium test in a Docker container is installing Docker as well as using the right tools in your tech stack.

This demo of using Selenium and Docker for test automation will use the following tools and technology:

  • Python, binded with Selenium WebDriver.
  • PyTest as a testing framework (you can use a framework of your preference, like Nose or JUnit)
  • IntelliJ IDEA as IDE
  • ChromeDriver, GeckoDriver (Firefox) or Headless Chrome
  • Docker.
  • CI tool, like Jenkins, or TeamCity. Add the plugins you need, like GitHub for the repository connection, Allure for reporting, BlazeMeter for performance testing, etc.

📕 Related Resource: Learn more about Selenium + GitHub: A Step-by-Step Testing Guide

Creating Your Selenium Test in Docker

1. If you want to make sure Docker is installed, open your console and write the command Docker –help. If you see a list of commands, it means that Docker is installed.

Docker installation

2. To check out which Docker images are installed, run docker images. An image has all the prerequisites needed for the tests. In the following steps, I will show you how to get images that you might be missing.

For example:

docker images repository

3. Create your Selenium test.

Let’s look at this test. The test is named test_purchase_tickets.py.

# coding=utf-8
import helpers.helpers as utils
import pytest
from selenium.webdriver.common.by import By


def submit_form(driver):
    driver.find_element(By.XPATH, "//input[@type='submit']").click()


def find_flight_in_dropdown(dropdown_element, expected_flight):
    for option in dropdown_element.find_elements_by_tag_name('option'):
        if option.text == expected_flight:
            option.click()


def choose_departure_flight(driver, departure_flight):
    from_port_dropdown = utils.find_element(driver, By.NAME, "fromPort")
    find_flight_in_dropdown(dropdown_element=from_port_dropdown, expected_flight=departure_flight)


def choose_arrival_flight(driver, arrival_flight):
    to_port_dropdown = utils.find_element(driver, By.NAME, "toPort")
    find_flight_in_dropdown(dropdown_element=to_port_dropdown, expected_flight=arrival_flight)


@pytest.fixture(scope="function")
def open_blazedemo(driver, url):
    driver.get(url)
    driver.find_element(By.TAG_NAME, "form")
    assert driver.title == "BlazeDemo"


@pytest.mark.parametrize('from_port, to_port', [
    ("Paris", "Buenos Aires"),
    ("Philadelphia", "Rome"),
    ("Boston", "London"),
    ("Portland", "Berlin"),
    ("San Diego", "New York"),
    ("Mexico City", "Dublin"),
    # fail on purpose to verify screenshot was added to allure report
    ("Tel Aviv", "Dubai")
])
def test_find_flights(driver, open_blazedemo, from_port, to_port):

    # Find flight
    choose_departure_flight(driver, departure_flight=from_port)
    choose_arrival_flight(driver, arrival_flight=to_port)
    submit_form(driver)

    assert from_port in utils.get_text(driver, By.TAG_NAME, "h3")
    assert to_port in utils.get_text(driver, By.TAG_NAME, "h3")
    assert "reserve.php" in driver.current_url

    # Choose flight
    submit_form(driver)

    assert from_port in utils.get_text(driver, By.TAG_NAME, "h2")
    assert to_port in utils.get_text(driver, By.TAG_NAME, "h2")
    assert "purchase.php" in driver.current_url

    # Purchase flight
    submit_form(driver)

    assert "Thank you for your purchase today!" in utils.get_text(driver, By.TAG_NAME, "h1")
    assert "confirmation.php" in driver.current_url


def test_teardown(driver):
    driver.quit()

 

This could be any test, according to the web application you need to be tested. This tests imports functions, imports PyTest, imports By from Selenium, tests blazedemo.com, and asserts several pages.

If we run the tests we can see they are working:

Selenium tests

4. Create and export the requirements.txt file, to implement your test in Docker. This file includes the packages needed to run the test. Use the command pip freeze > requirements.txt.

The requirements will look like this:

arrow==0.8.0
colorama==0.3.7
enum34==1.1.6
lxml==3.6.0
moment==0.5.1
namedlist==1.7
py==1.4.31
pytest==2.7.3
pytest-allure-adaptor==1.7.7
pytest-gitignore==1.3
python-dateutil==2.5.3
pytz==2016.4
selenium==2.53.5
six==1.10.0
times==0.7

 

5. Now it’s time to create a base Dockerfile to support Selenium, Chrome, and Firefox:

FROM python:2.7-stretch

RUN apt-get update && apt-get install -yq \
    firefox-esr=52.6.0esr-1~deb9u1 \
    chromium=62.0.3202.89-1~deb9u1 \
    git-core=1:2.11.0-3+deb9u2 \
    xvfb=2:1.19.2-1+deb9u2 \
    xsel=1.2.0-2+b1 \
    unzip=6.0-21 \
    python-pytest=3.0.6-1 \
    libgconf2-4=3.2.6-4+b1 \
    libncurses5=6.0+20161126-1+deb9u2 \
    libxml2-dev=2.9.4+dfsg1-2.2+deb9u2 \
    libxslt-dev \
    libz-dev \
    xclip=0.12+svn84-4+b1

# GeckoDriver v0.19.1
RUN wget -q "https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz" -O /tmp/geckodriver.tgz \
    && tar zxf /tmp/geckodriver.tgz -C /usr/bin/ \
    && rm /tmp/geckodriver.tgz

# chromeDriver v2.35
RUN wget -q "https://chromedriver.storage.googleapis.com/2.35/chromedriver_linux64.zip" -O /tmp/chromedriver.zip \
    && unzip /tmp/chromedriver.zip -d /usr/bin/ \
    && rm /tmp/chromedriver.zip

# xvfb - X server display
ADD xvfb-chromium /usr/bin/xvfb-chromium
RUN ln -s /usr/bin/xvfb-chromium /usr/bin/google-chrome \
    && chmod 777 /usr/bin/xvfb-chromium

# create symlinks to chromedriver and geckodriver (to the PATH)
RUN ln -s /usr/bin/geckodriver /usr/bin/chromium-browser \
    && chmod 777 /usr/bin/geckodriver \
    && chmod 777 /usr/bin/chromium-browser

This base Dockerfile creates a new, isolated container that includes everything you need to run Selenium to read Chrome.

Or, instead of creating the base Dockerfile, you can use Docker Hub, search for “Selenium” and use one of the ~2000 containers that are already there.

use docker hub for selenium

To use an image from Docker Hub, simply click on it and copy the pull command:

Using an image from Docker Hub in an automated Selenium test.

Now, put the command in the Dockerfile in the From section. When the test is run, Docker will pull the image from the cloud.

The benefit of using the Docker Hub method is that you don’t have to handle the Dockerfile by yourself. This is also a limitation - you have no flexibility or control over containers. In my opinion, the flexibility that Docker provides is worth the effort.

In your base Dockerfile, make sure you specify the package version you want to test, so the browsers are tested correctly.

The test shown here includes:

  • Downloading the browsers’ WebDriver (Gecho Driver, Chrome Driver)
  • X Server Display - this is important because there is no UI, so you must install it to have a visual view of the test.
  • Symlinks to the web drivers, to connect everything together

6. Store the base DockerFile in the Root folder.

7. Create a project Dockerfile to support requirements.txt. This will be the Docker file that uses the base image:

FROM blazemeter/selenium-framework

# create project folder with the name code
RUN mkdir /code

# project scope
WORKDIR /code

# install requirements
COPY requirements.txt .
RUN pip install -r requirements.txt

# Set Dokcer entry
COPY docker-entry.sh /code
ENTRYPOINT ["/code/docker-entry.sh"]

 

8. Store this Docker base file in the project root.

9. Create a Bash script to orchestrate your test (and make your life easier).

#!/usr/bin/env bash

# Declaring pytest arguments
export PYTEST_ARGUMENTS=${@:-tests/test_purchase_tickets.py}

# Set tag names to folders
export AUTOMATION_IMAGE=blazemeter/selenium-framework
export PROJECT_IMAGE=blazemeter/blazedemo-app-selenium

export ALLURE_RESULTS_DIR=allure-results
export PROJECT_DIR=blazedemo_app

# Create tags for selenium-base-image and the project folder
docker build selenium-base-image -t ${AUTOMATION_IMAGE}
docker build ${PROJECT_DIR} -t ${PROJECT_IMAGE}


# Run Selenium py.test with script arguments
# Map allure output xml to image folder
# Map root folder to image folder
# Set the working directory as the root folder in the image
# Set the PYTHONPATH to the root folder in the image
# Run the project image as declared above
docker run --rm \
    -v $(pwd)/$PROJECT_DIR/$ALLURE_RESULTS_DIR:/code/$ALLURE_RESULTS_DIR \
    -v $(pwd)/blazedemo_app/:/code/ \
    -w=/code \
    -e PYTHONPATH=/code/ \
    ${PROJECT_IMAGE} \
    "$PYTEST_ARGUMENTS"

 

The Bash script declares PyTest arguments, sets tag names, runs the Selenium test, runs the project image, generates an XML from the results, and more.

10. We are ready to run the script! Run the command:

/scripts/run-tests.bash --env=$ENV tests/test_purhcase_tickets.py -v

This command runs the bash file, and also points to the specific test to run.

The command in Selenium created a container from the base Docker file. The first time this happens it will take a few minutes because the container needs to be installed. But next time, the test will run much quicker.

automated selenium with docker

11. The tests are being run and you can see the results:

Results of Selenium test in Docker

Reporting for Selenium Tests in Docker

Now, let us see how we can view the results in a visual manner that is easy to analyze.

12. Create a script to generate test results

#!/usr/bin/env bash

# pull allure report image from docker hub
ALLURE_IMAGE=beeete2/docker-allure2

# create relevant folder structure for allure report
ALLURE_CONFIG_DIR=allure-config
ALLURE_REPORT_DIR=allure-report
ALLURE_RESULTS_DIR=allure-results
PROJECT_DIR=${1:-blazedemo_app}

# Delete any previous allure reports
rm -rf $PROJECT_DIR/$ALLURE_REPORT_DIR

# run allure image to generate allure report based on latest test results
docker run --rm \
    -v $(pwd)/$PROJECT_DIR/$ALLURE_REPORT_DIR:/$ALLURE_REPORT_DIR \
    -v $(pwd)/$PROJECT_DIR/$ALLURE_RESULTS_DIR:/$ALLURE_RESULTS_DIR \
    -v $(pwd)/$PROJECT_DIR/$ALLURE_CONFIG_DIR:/$ALLURE_CONFIG_DIR \
    $ALLURE_IMAGE allure generate /$ALLURE_RESULTS_DIR -o /$ALLURE_REPORT_DIR

This script takes allure2 from the Docker hub. It maps the actual allure report that’s being created, will create an XML and a png file, and will create three more folders.

13. To generate the Allure report, run the command:

./scripts/generate-allure-report.bash blazedemo_app

14. To generate the Allure report, run:

cd ./blazedemo_app/allure-report/
python -m SimpleHTTPServer 8080
open http://localhost:8080

This command includes the folder to store the reports in, the creation of a Python server for the reports, and the presentation in port 8080 (for example).

15. Now, if you go to localhost, you will see the reports:

Allure Selenium reporting

This report has been generated from the XML file. As you can see 8 tests are being executed. You can also click on the tests to get more details, like duration, or failure reasons.

selenium, docker and allure reports

Bottom Line

That’s it! This has been an overview of how to run a Selenium test in Docker. To learn more about Selenium, Docker, and more, you may find the following blog posts helpful:

You can also skip all these steps and upload your functional test script (in java and yaml) to BlazeMeter, and easily run your test.

BlazeMeter functional test

Don't miss the chance to experience BlazeMeter in action. Try out BlazeMeter for free today. 

START TESTING NOW

Related Resources: 

This blog was originally published on April 2, 2018, and has since been updated for accuracy and relevance.