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.
This post is part of my journey to learn Python. You can find the other parts of this series here. You find the code for this post in my PythonFriday repository on GitHub.
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:
1 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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:
1 |
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 itemselenium_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.