You'll need the following commands available on your system to run the test cases:
- bash
- coreutils (id, rm, cd, cat, printf, ...)
- docker
- docker-compose
- git
- make
- python 2.7+
- vncviewer (macosx users can launch vnc from spotlight, or the
open
command in the terminal)
Make sure you also have a copy of the this repository. You can get a copy by executing the following commands in your terminal.
cd ${REPOBASE};
git clone https://github.com/dskard/seleniumconf2018.git dskard-seleniumconf2018;
cd dskard-seleniumconf2018;
Where ${REPOBASE}
is the directory where you download repositories to.
The Selenium based tests in this directory use web browsers provided by
Selenium Grid Docker containers. These Docker containers can be launched and
torn down, separate from running the tests, by using the test-env-up
and
test-env-down
local Makefile targets.
A typical workflow for running tests may look like this:
# launch the Selenium Grid containers once
# at the beginning of the testing session
make test-env-up
# run all of the test
make test
# run a single test multiple times
make test PYTESTOPTS="t/test_front_page_search.py::TestFrontPageSearch::test_search_1"
make test PYTESTOPTS="t/test_front_page_search.py::TestFrontPageSearch::test_search_1"
make test PYTESTOPTS="t/test_front_page_search.py::TestFrontPageSearch::test_search_1"
# tear down the Selenium Grid containers
# at the end of the testing session
make test-env-down
In this example workflow, we launch the Selenium Grid containers, which host
the Firefox and Chrome web browsers, once at the beginning of the testing
session by using the test-env-up
Makefile target. The test-env-up
target is
responsible for launching all Docker containers that make up the testing
environment. That includes the web browser containers from the Selenium Grid
along with any other support containers that may be needed to run the tests
like mail servers, LDAP servers, and databases.
With the support containers launched, test cases can be run by using the test
Makefile target. The test
target launches a separate Docker container that
hosts the pytest
test runner process. The container communicates with the
other support containers over a virtual Docker network. Attributes of the
test
target can be tuned by setting a number of environment and Makefile
variables. The most often used of these variables is PYTESTOPTS
, used to set
flags for the pytest
test runner, like filtering the test cases to be run. A
list of all available variables is shown in the next section. Test cases can be
run multiple times against the same support containers and system under test.
This is helpful when trying to write or debug test cases during the development
cycle, where the developer may need to rerun tests multiple times without the
cost of launching the tearing down the test environment.
When the testing session has finished, the support containers can be torn down
by using the test-env-down
Makefile target. This target is responsible for
shutting down all of the Docker containers that were launched with the
test-env-up
target.
Under the hood, the Makefile's test
target uses pytest
as the test runner.
You can pass custom pytest
flags via PYTESTOPTS
. Here we are passing -v
which enables verbosity and -x
which enables fast fail.
make test PYTESTOPTS="-xv"
If you want to test a specific feature, you can also use the PYTESTOPTS
Makefile variable to select a collection of tests.
# test a directory
make test PYTESTOPTS="t"
# test a specific file
make test PYTESTOPTS="t/test_front_page_search.py"
# test a class within a file
make test PYTESTOPTS="t/test_front_page_search.py::TestFrontPageSearch"
# test a specific test within a class of a specific file
make test PYTESTOPTS="t/test_front_page_search.py::TestFrontPageSearch::test_search_1"
You can find an exhaustive list of pytest flags in the pytest documentation. In the table below are listed the handful of pytest flags that pop up frequently in daily use for configuring how and which test cases are executed.
Flag | Description | Example | Link |
---|---|---|---|
-x | Stop execution after the first (or N) failures | PYTESTOPTS="-x" |
Learn more |
-k expression | Run tests by keyword expressions | PYTESTOPTS="-k ClassName and not (method1 or method2)" |
Learn more |
-m expression | Run tests by marker expressions, markers are set as @pytest.mark.marker1 or @pytest.mark.marker2 |
PYTESTOPTS="-m marker1 or marker2" |
Learn more |
--pdb | Drop into PDB (Python Debugger) on failures | PYTESTOPTS="--pdb" |
Learn more |
--count=10 | Repeat each test case 10 times | PYTESTOPTS="--count=10" |
Learn more |
--durations=0 | Profile test case execution. Print the time duration of each test case. | PYTESTOPTS="--durations=0" |
Learn more |
--rerun=4 | Rerun test case failures a maximum of 4 additional times, waiting for success | PYTESTOPTS="--rerun=4" |
Learn more |
--test-group-count=10 | Specify the number of test groups. Must be used with --test-group flag. Primarily used for running test cases in parallel on different Jenkins nodes. |
PYTESTOPTS="--test-group-count=10" |
Learn more |
--test-group=2 | Specify which group of tests to execute. Must be used with --test-group-count . Primarily used for running test cases in parallel on different Jenkins nodes. |
PYTESTOPTS="--test-group=2" |
Learn more |
--test-group-random-seed=12345 | Randomize the grouping of test cases. Must be used with --test-group-count and --test-group flags. Primarily used for running test cases in parallel on different Jenkins nodes. |
PYTESTOPTS="--test-group-count=10 --test-group=2 --test-group-random-seed=12345" |
Learn more |
Although it is not a pytest command line flag, when placed inside a test case,
import pdb; pdb.set_trace()
sets a Python Debugger breakpoint within the test
case. When the Python interpreter reaches this breakpoint, it will drop into
the Python Debugger and allow you to interactively step through the test case
code and print the values of variables. You can learn more about its use in the
Setting
breakpoints
section of the pytest
documentation
You can use the BROWSER
Makefile variable to set the web browser used in the
test run. By default, we test against the Firefox web browser by setting
BROWSER=firefox
. Valid option for the BROWSER
variable are firefox
and
chrome
.
This feature can be combined with the any of the other test running techniques discussed previously.
make test BROWSER=chrome
make test PYTESTOPTS="t/test_front_page_search.py" BROWSER=firefox
The Makefile includes a run
target that can be used to launch a Docker
container running on the same Docker network as the Selenium Grid and the
system under test. Enter the debug container with the command:
make run
The default command for the debug container is bash
, but this can be changed
by setting the COMMAND
Makefile variable. Another common command is to start
a Python3 interpreter:
make run COMMAND=ipython3
From the Python3 interpreter, Python commands can be executed to open a web browser and navigate it to the system under test:
# import the Selenium library to automate the web browser
from selenium import webdriver
# import the Selene library to help simplify browser automation
# Selene uses the Selenium library
from selene.api import browser, s, ss, be, have, by
# set the url of the system under test
url = 'http://google.com'
# launch the web browser
driver = webdriver.Remote("http://selenium-hub:4444/wd/hub", webdriver.DesiredCapabilities.FIREFOX.copy())
# associate the WebDriber object with the Selene library
browser.set_driver(driver)
# navigate the web browser to the system under test
browser.open_url(url)
# load functions from conftest
# not used in this example
from conftest import log_web_error
# use the Selene library directly to interact with the web page
# navigate the web browser to the system under test
browser.open_url(url)
# type "cheese" into the search field
s('[name="q"]') \
.set_value('cheese')
# click the "Google Search" button
s('[name="btnK"]') \
.click()
# check that results are shown
s('#resultStats') \
.should(be.visible)
# use page objects to interact with the web page
# load page objects
from t.pages.front_search_form import FrontSearchForm
from t.pages.app_bar import AppBar
# navigate the web browser to the google search page
browser.open_url(url)
# search for "cheese"
form = FrontSearchForm()
form.search_box.set_value('cheese')
form.submit.click()
# check that results are shown
appbar = AppBar()
appbar.result_stats.should(be.visible)
# close the web browser
browser.quit()
A number of environment and Makefile variables are available to tune the test environment. Adjusting these variables change things like the types and number of web browsers available for testing, the hostname and port of the Selenium Grid, and the options accepted by the test runner program.
Specify the web browser to use for testing, chrome
or firefox
.
Default Value: "firefox"
Example usage:
make test BROWSER=firefox
Command to run inside of the debug container started with the make run
command.
Default Value: bash
Example usage:
make run COMMAND=python3
File path of the Selenium Grid Docker Compile YAML config file.
Default Value: ./docker/grid/docker-compose.yml
Example usage:
make test-env-up DCYML_GRID=./docker/grid/docker-compose.yml
Setup the test environment for debugging tests. For example, disable GRID_TIMEOUT by setting it to 0. See below for details on GRID_TIMEOUT.
Default Value: 0
Example usage
DEBUG=1 make test-env-up
Command to launch a Docker container for both make test
and make run
commands. This variable does not include the command that will run inside of
the Docker container. In most cases you will not need to change this variable.
Default Value:
DOCKER_RUN_COMMAND=docker run -it --rm --init \
--name=tre-${HOURMINSEC} \
--network=$(NETWORK) \
--volume=${CURDIR}/../..:${CONNECT_DIR} \
--user=`id -u`:`id -g` \
--workdir=${CONNECT_DIR}/test/selenium \
-e PYTHONPATH="${CONNECT_DIR}/test" \
${SELENIUM_IMAGE}
Example usage: Not meant to be changed
Name of the Docker container hosting the Selenium Grid hub.
Default Value: selenium-hub
Example usage:
make test GRID_HOST=selenium-hub
Port number of the Docker container hosting the Selenium Grid hub.
Default Value: 4444
Example usage:
make test GRID_PORT=4444
Number of milliseconds the Selenium Grid Hub should wait before automatically closing a web browser due to inactivity. This value is also set by the DEBUG variable.
Default Value: 30000
Example usage:
make test-env-up GRID_TIMEOUT=30000
Timestamp used as a part of a Docker container name.
Default Value: date +'%H%M%S'
Example usage:
make run HOURMINSEC=`date +'%y%m%d-%H%M%S'`
Directory where log files should be store. Primarily used by wait_for_systems_up.sh
Default Value: ${WORKDIR}
Example usage:
make LOGS_DIR=\${WORKDIR}
Full name of the virtual Docker network, based on PROJECT variable
Default Value: ${PROJECT}_default
Example usage:
make test-env-up NETWORK=templatenet_default
Name used as the base of the virtual Docker network
Default Value: templatenet
Example usage:
make test-env-up PROJECT=templatenet
Name of the file to store pytest stdout into.
Default Value: selenium_tests.log
Example usage:
make test PYTESTLOG=selenium_tests.log
Flags and filters to pass to the test runner program. These flags can change the behavior of the test runner program by helping to determine which test cases to run, what to do when a test case fails, or by injecting data into the test runner.
Default Value: ""
Example usage:
make test PYTESTOPTS="t/test_front_page_search.py::TestFrontPageSearch::test_search_1"
make test PYTESTOPTS="t/test_front_page_search.py::TestFrontPageSearch::test_search_1"
make test PYTESTOPTS="-k test_search_1 -xv"
Number of times to try rerunning a test failure. When a test failure occurs, this value tells the test runner how many times to rerun the test in an attempt to get a successful run. If all rerun attempts fail, the test will show up as failed in the results. If one attempt passes, the failed attempts will show up in the test results as reruns, but the results will show that the test passed. This variable accepts zero and positive integers. Setting this value may hide flaky test failures.
Default Value: 0
Example usage:
make test RERUN_FAILURES=4
Name of the file holding pytest's junit style xml results.
Default Value:result.xml
Example usage:
make test RESULT_XML=result.xml
Number of Firefox and Chrome web browsers to launch
Default Value: 1
Example usage:
make test-env-up SCALE=1
Number of Chrome web browsers to launch, does not affect Firefox web browsers
Default Value: ${SCALE}
Example usage:
make test-env-up SCALE_CHROME=2
Number of Firefox web browsers to launch, does not affect Chrome web browsers
Default Value: ${SCALE}
Example usage:
make test-env-up SCALE_FIREFOX=2
Version of the Selenium Grid Docker images
Default Value: 3.8.1-dubnium
Example usage:
make test-env-up SELENIUM_VERSION=3.8.1-dubnium
URI hostname of the system under test
Default Value: www.google.io
Example usage:
make test SUT_HOST=www.google.io
URI port number of the system under test
Default Value: 443
Example usage:
make test SUT_PORT=443
URI scheme of the system under test
Default Value: https
Example usage:
make test SUT_SCHEME=https
Command to launch the test runner program.
Default Value:
pytest \
--junitxml=${RESULT_XML} \
--driver=Remote \
--host=${GRID_HOST} \
--port=${GRID_PORT} \
--capability browserName ${BROWSER} \
--bundles-dir=${CONNECT_BUNDLES} \
--url=${URL} \
--verbose \
${PYTESTOPTS} \
.
Example usage:
make test TEST_RUNNER_COMMAND="pytest"
Name of the temporary pipe file used to capture stdout from pytest. Do not change.
Default Value: tmp.pipe
Example usage:
make test TMP_PIPE=tmp.pipe
Name of the Test Runner Environment (TRE) Docker image. This image hosts the
test runner, pytest
, and should include all software needed to run the test
cases.
Default Value: dskard/tew:0.1.0
Example usage:
make test TRE_IMAGE=dskard/tew:0.1.0