Module 2 · Python for SDETs

Fixtures & parametrize

Stop repeating setup — and run one test over many inputs

fixtures yield scope parametrize
AI with Rufat
Fixtures = reusable setup

A test asks; pytest provides

@pytest.fixture
def base_url():
return "http://localhost:3000"
def test_products(base_url):
r = requests.get(base_url + "/api/products")
assert r.status_code == 200
💡The test names the fixture as a parameter; pytest runs it and injects the return value. That's dependency injection — no manual calls.
AI with Rufat
yield — setup before, teardown after

One function, both halves

BEFORE yield
setup
session = requests.Session()
yield
the test runs
yield session
AFTER yield
teardown
session.close()
🛡️Teardown runs even if the test fails — it replaces try/finally for cleanup.
AI with Rufat
Scope — isolation vs speed

How often a fixture runs

scope="function"once per test · the default · most isolated
scope="class"once per test class
scope="module"once per .py file
scope="session"once per whole run · fastest · shared state
⚖️Use the narrowest scope that's correct. Widen only for read-only or safe-to-share setup (like base_url).
AI with Rufat
One test, many inputs
@pytest.mark.parametrize(
"category",
["electronics", "accessories", "furniture"],
)
def test_category(category):
# runs once per row
pytest -v
test_category[electronics] PASSED
test_category[accessories] PASSED
test_category[furniture] PASSED
One function → three independent results. Add a case = add a row. Name them with ids=.
AI with Rufat
🧩

Setup, shared & clean

Fixtures inject setup · parametrize covers the table · conftest.py shares both

📁
conftest.py
Shared base_url / api / reset_db — found automatically, no import
🏷️
Markers
Tag tests (smoke/api) and select with -m; skip / xfail built in
➡️
Module 3
API testing with requests — every HTTP verb against the app
AI with Rufat
← / → · space