Skip to content

#147: End-To-End Tests With Selenium and Pytest

Selenium is great to automate repetitive task in a web browser. We can take that concept one step further and use it to create end-to-end tests for web applications. Today we look at an approach to keep the initialisation code for Selenium in one place and use it in as many tests as we need.

Remember pytest fixtures?

Pytest has the useful concept of a fixture that allows us to inject code into our test cases with a decorator. We can build on top of the post on creating our own fixtures for pytest and encapsulate the whole code to initialise a web browser. That way our tests concentrate on testing the software, while our fixture makes sure that we get the right browser to run the end-to-end tests.

Before we start with our own fixture, we should check that we have the current version of pytest:

pip install -U pytest

Creating a fixture for Selenium

We can take the code to set-up Selenium and put it into our browser() fixture:

import pytest
from selenium.webdriver.firefox.service import Service
from selenium import webdriver
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.common.by import By
import time
from dotenv import load_dotenv
import logging


@pytest.fixture()
def browser():
    """Creates a Firefox browser to run your tests"""
    load_dotenv()
    logging.getLogger('WDM').setLevel(logging.NOTSET)

    driver = webdriver.Firefox(
        service=Service(GeckoDriverManager().install()))
    driver.implicitly_wait(2)

    # runs your test
    yield driver

    driver.close()

The yield statement is the place in which our test code will run. That way we create a Firefox browser and dispose of it after the test run in the same fixture.

Use the fixture in your test

In our test file we import our browser fixture and use it like any other fixture:

1
2
3
4
5
6
7
8
import pytest
from selenium_pytest_fixture import browser


@pytest.mark.usefixtures("browser")
def test_duckduckgo(browser):
    browser.get("https://duckduckgo.com/?t=ha&va=j")
    assert "DuckDuckGo — Privacy, simplified." == browser.title

This test will get its Firefox browser from the fixture, opens DuckDuckGo.com and checks if the title is what we expect. From this basic set of commands, we can grow our test to whatever we need.

Run the test

We can run our end-to-end test with this command:

pytest .\selenium_pytest_test.py

This should give us a successful test run:

=================== test session starts ===================
platform win32  Python 3.10.8, pytest-7.1.3, pluggy-1.0.0
rootdir: C:\_Projects\PythonFriday\Selenium
plugins: cov-3.0.0, pythonpath-0.7.3
collected 1 item

selenium_pytest_test.py . [100%]

=================== 1 passed in 7.70s ===================
 

Next

With a fixture in pytest we can organise our Selenium set-up code in a reusable way. This will be sufficient for the first steps in end-to-end testing. Great things tend to attract requests for new features, and so you will soon need to take videos or screenshots of your tests. Next week we will explore Selenium Grid and see how we can fulfil these requests.