Noga Cohen is a Sr. Product Marketing Manager for CA BlazeMeter. She manages the BlazeMeter blog and other content activities. Noga focuses on creating technological content in the fields of performance, load testing and API testing, both independently and by managing writers who are developers. Noga has more than 5 years of experience in a wide scope of writing techniques: hi-tech, business, journalist and academic.

Learn JMeter in 5 Hours

Start Learning
Slack

Run massively scalable performance tests on web, mobile, and APIs

Apr 02 2018

How to Run Selenium Tests in Docker

Selenium WebDriver is a powerful and flexible tool that enables you to run functional tests on your web applications. 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. It is based on a webinar by performance automation engineer Eliran Shani which you can view here. All scripts can also be found on GitHub, here.

 

What is Selenium WebDriver?

 

Before discussing Selenium WebDriver, let’s explain what Selenium is. Selenium is an open source tool that automates web browsers and web applications. As it runs across many browsers and operating systems and supports multiple programming languages and testing frameworks, there are endless possibilities to its testing capabilities. So, what you decide to do with it is up to you.

 

Selenium has three major tools. 1. Selenium IDE, a tool that reproduces scripts by recording and playing them back. Selenium IDE is more or less deprecated. 2. Selenium Server (Grid) for running tests in parallel on different machines. 3. Selenium WebDriver, a robust, browser-based regression automation suite, which enables distributing tests across many environments. This blog post will discuss Selenium WebDriver.

 

Selenium WebDriver Benefits

 

  • Selenium WebDriver is open source, making it free and portable and open to contributions of people from all over the world. In addition, you can learn Selenium from discussions and resources across the web that are open to everyone. On the other hand, it has no official support.
  • Selenium WebDriver supports many languages, including Python, C Sharp and Java. This enables flexibility when using it as well as making it accessible to many developers. However, Selenium requires experience and understanding of its abilities and way of work.
  • Selenium WebDriver supports many browser types, operating systems and platforms, including mobile browsers, android, Windows, etc. However, the tester needs to be in sync with all the updates to ensure smooth testing.
  • Selenium WebDriver is valuable for Continuous Integration development by working with CI tools, enabling developers to add functional testing to their Continuous Testing process. However, Selenium does not have inbuilt reporting capabilities, so it requires installing 3rd party plugins.

 

What is Docker?

 

Docker is a software containerization platform that provides virtualization from the operating system level. In Docker, all software parts can be organised 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) on the web 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 in bare metal speed.

 

Prerequisites

 

This blog post shows a demo that uses the following tools:

  • 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 (install here)
  • 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.

 

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.

 

create selenium tests in docker

 

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

 

For example:

 

run selenium through docker

 

3. Create your Selenium test.

 

Let’s look at this test, which you can also find here. 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:

 

run docker for functional 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 (you can also find them here):

 

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:

 

run functional tests with selenium and docker

 

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 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 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 webdrivers, 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 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:

 

selenium test results

 

Reporting

 

Now let’s 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 create 3 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:

 

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

 

That’s it! This has been an overview of how to run a Selenium test in Docker. To learn more about Selenium, you can read these blog posts:

View the complete webcast from this link, and learn how to create your own Selenium Docker script, just like this one:

 

how to run selenium through docker guide

 

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

 

using selenium with docker tutorial

 

Stay updated on how you can integrate BlazeMeter with your Selenium tests by signing up here. To see BlazeMeter in action, request a demo.

Interested in writing for our Blog?Send us a pitch!

Your email is required to complete the test. If you proceed, your test will be aborted.