Mozilla Internship: Writing a pytest Fixture

Writing a pytest fixture was actually much easier to do than I expected.

I did find, however, that the documentation on custom pytest fixtures was not very applicable to my situation.

I instead spent quite a lot of time looking at other pytest fixtures, such as pytest-html, pytest-selenium, and pytest-base-url, trying to figure out how they worked.

Having never used pytest fixtures—and being new to pytest—it was a bit of a struggle for me to really understand what was going on.

The most applicable examples that I looked at were pytest-selenium and pytest-base-url.

pytest-selenium and pytest-base-url

The main purpose of the pytest-selenium package is that it takes care of the setup and tear down processes for you.

The selenium fixture essentially instantiates and return a webdriver instance.

The fixture also closes the instance for you at the conclusion of your test function.

If base_url is defined in a config file or passed in as a command line argument, pytest-selenium will use this value and load the page automatically at the execution of your test function.

Using pytest-selenium can simplify something like this:

from selenium import webdriver

def test_python_page_title():
    driver = webdriver.Firefox()
    driver.get("http://www.python.org")
    assert "Python" in driver.title
    driver.close()

to this:

def test_python_page(selenium):
    assert "Python" in selenium.title

While pytest-selenium has many more capabilities, and is a complex package, this seems to be the primary purpose, at least as I understand it.

pytest-axe

pytest-axe is a pytest fixture similar to pytest-selenium, albeit it is extremely simple in comparison.

This package takes a selenium instance and instantiates an instance of the Axe class for you.

It also finds the axe.min.js script in the axe-selenium-python package, and Axe sets it as a class-level variable in its constructor.

I decided to create this fixture to make it easier for users to integrate my axe-selenium-python API into their test suites.

The easier it is to use, the more likely people are to use it.

To illustrate just how basic this package is, this code is the entire functionality of the plugin:

pytest_axe.py

import pytest
from axe_selenium_python import Axe


@pytest.fixture
def axe(selenium, base_url):
    """Return an Axe instance based on context and options."""
    selenium.get(base_url)
yield Axe(selenium)

I originally implemented this fixture by adding it to conftest.py within the test files in my axe-selenium-python package.

Again, I was surprised at how easy it was to get this to work. It did take some fiddling around, but altogether, very little time was spent on this.

I moved this fixture into a package by itself, because I don’t want users to have to manually add the fixture into their conftest.py file.

At best, this would be quite annoying. More than likely, people just wouldn’t use it.

Syntax Highlighting by EnlighterJS

About the Author

Kimberly is currently a Test Automation Engineer for Mozilla, with a focus on automating web accessibility testing.

While she always enjoys learning new technologies, her current focus is python, and when she has free time (she doesn't), she enjoys JavaScript programming and learning about Data Analysis.

When not coding, Kimberly spends time with her three young boys, brand new baby girl, and her partner, in Durango, CO.