UI Automation: Selenium + Playwright + pytest · Lesson 4 of 6

pytest Deep-Dive: Fixtures, conftest, Parametrize & Markers

pytest is the engine that runs your tests in both stacks. Four features do most of the heavy lifting — learn these and you're most of the way there.

By Shahriyar · Updated

The idea, in one line

pytest lets you set things up once, run one test across many inputs, and label tests so you can pick which ones run.

1. Fixtures — setup and cleanup

A fixture prepares something a test needs (like an open browser) and cleans it up afterward. Decorate a function with @pytest.fixture, then any test that names it as a parameter receives its value.

Control how long a fixture lives with scope: function (the default), class, module, package, or session. A logged-in browser is a natural session or module fixture — set it up once, reuse it.

2. conftest.py — the shared shelf

Put shared fixtures in a file called conftest.py. No import needed: every test in that folder and below can just ask for them by name.

3. parametrize — one test, many inputs

@pytest.mark.parametrize runs the same test body across a list of inputs, each reported as its own case. Wrap a single row in pytest.param(..., marks=..., id=...) to give it a name or a tag.

4. Markers — labels you can filter on

Markers tag tests — @pytest.mark.smoke, @pytest.mark.regression — so you can run just a group with pytest -m smoke. Register them in pyproject.toml and add --strict-markers so a typo fails loudly instead of silently skipping.

See it work

▸ try it
# conftest.py — a shared fixture, no import needed below
import pytest
from playwright.sync_api import sync_playwright

@pytest.fixture(scope="session")
def browser():
    with sync_playwright() as p:
        b = p.chromium.launch()
        yield b        # tests run here
        b.close()      # cleanup after the whole session

# test_search.py
import pytest

@pytest.mark.smoke
@pytest.mark.parametrize("term,hits", [
    ("backpack", 1),
    ("jacket", 1),
    pytest.param("", 6, id="empty-shows-all"),
])
def test_search_counts(term, hits):
    assert search(term) == hits   # runs 3 named cases

# pyproject.toml
# [tool.pytest.ini_options]
# markers = ["smoke: fast critical-path checks"]

Read it top to bottom: the browser fixture opens Chromium once and closes it at the end. The test runs three times, once per input row, and the smoke tag lets you single it out later.

Grounded in the official pytest docs — Fixtures, Parametrize, Markers

All lessons in UI Automation: Selenium + Playwright + pytest

  1. Selenium Locators: Finding the Element You Mean
  2. Waits, Actions & Frames — Killing Flakiness at the Source
  3. Playwright: Auto-Waiting, Locators & Tracing
  4. pytest Deep-Dive: Fixtures, conftest, Parametrize & Markers
  5. Page Object Model, Done Properly
  6. The Hard Stuff: Dynamic Elements, iframes, Uploads & Network Stubbing