Module 8 · Python for SDETs

Data-driven
tests

One test body, many cases — from a table, a JSON file, or a CSV

parametrize JSON & CSV readable ids data ≠ logic
AI with Rufat
Separate the cases from the code

One test body, a table of cases

a list of cases
@parametrize over it
N independent, labeled tests
🧩Add a row, get a test — the body never changes. Each case runs (and fails) independently, so one bad input doesn't hide the rest.
AI with Rufat
Data from a JSON file
tests/data/login_cases.json
[
{ "email": "customer@test.io",
"password": "customer123", "expected": 200 },
{ "email": "ghost@test.io",
"password": "x", "expected": 401 }
]
CASES = json.loads(
(Path(__file__).parent / "data"
/ "login_cases.json").read_text()
)
@pytest.mark.parametrize("case", CASES)
def test_login(case): …
📂Load at module levelparametrize runs at import, so the data must exist by then. (JSON file = no // comments.)
AI with Rufat
CSV: every value is a string
# tests/data/categories.csv
category,present
electronics,true
nonexistent,false
rows = csv.DictReader(f)
present = row["present"] == "true"
🔤csv.DictReader yields one dict per row, but every value is a string — so "false" is truthy!
🔁Convert types yourself: compare == "true", or wrap in int(...) — the reader won't do it for you.
AI with Rufat
Give each case a readable name
No ids — opaque
test_login[case0]
test_login[case1]
test_login[case2]
ids from the data
ids=[f"{c['email']}->{c['expected']}"
for c in CASES]
test_login[customer@test.io->200]
test_login[ghost@test.io->401]
AI with Rufat
🧮

Cases as
data

One body, many rows — from JSON or CSV, each named so failures point at the case

🧪
Practice
A login matrix from JSON: valid→200, wrong→401, empty→400
🔤
CSV types
Read categories.csv and remember to convert the strings
➡️
Module 9
Reporting & suite structure — HTML reports, markers, folders
AI with Rufat
← / → · space