FR EN
Data-Driven Testing: Complete Guide with Python
Data-Driven Testing: Complete Guide with Python — AutomationDataCamp
April 25, 2026 · Updated September 29, 2026 Oussama Belakhdar 8 min read

Data-Driven Testing: Complete Guide with Python

Data-driven testing (DDT) means writing a test once and running it against many sets of input data and expected results stored outside the test logic: in a parameter list, a CSV or JSON file, a spreadsheet or a database. In Python, the simplest way to do it is pytest's @pytest.mark.parametrize decorator. This guide explains when DDT is worth it, how to implement it with pytest and each data source, and how to manage test data without making the suite fragile.

Key takeaways
  • pytest.mark.parametrize: one decorator turns each data row into a separate test, reported and re-runnable on its own
  • Choose the source by who maintains the data: inline lists for developers, CSV or JSON in Git for shared data, Excel for business teams, a database for live state
  • Test isolation is mandatory: each data row must run independently, never relying on data created by another test
  • Design the rows with test techniques such as equivalence partitioning and boundary value analysis, rather than adding rows at random

What is data-driven testing?

Data-driven testing is a test design approach in which the test logic is written once and the inputs and expected outputs come from a separate data set. The same scenario, for example "apply a discount code and check the total", runs once per data row. Adding a case means adding a row, not writing new code.

The approach increases coverage without duplicating test code, and it lets people who do not write code, such as business analysts, review or extend the test cases directly in the data file.

When should you use data-driven testing?

Use it when the same behaviour must be checked against many input combinations: calculations, validation rules, pricing, permissions, form fields or API payloads. Avoid it when each case needs different steps: forcing different scenarios into one parameterised test produces conditional logic that is harder to read than separate tests.

How do you do data-driven testing with pytest?

Decorate the test function with @pytest.mark.parametrize, name the arguments and pass a list of tuples. pytest generates one test item per tuple, so each case passes or fails on its own and appears separately in the report.

For example, @pytest.mark.parametrize("price, discount, expected", [(100, 0, 100), (100, 10, 90), (100, 25, 75)]) above def test_discount(price, discount, expected) produces three tests. Useful options:

  • Readable names: pass ids=[...], or wrap a row in pytest.param(..., id="ten-percent"), so the report says which case failed
  • Known bugs: pytest.param(..., marks=pytest.mark.xfail) keeps a failing row visible without breaking the build
  • Combinations: stacking two parametrize decorators runs every combination of both lists
  • Dynamic data: the pytest_generate_tests hook in conftest.py parameterises tests from any source at collection time

Avoid the alternative of looping over the data inside a single test: the first failing row stops the loop, the remaining rows never run, and the report shows one failure instead of telling you which cases broke.

Which data source should you use: CSV, JSON, Excel or a database?

Pick the source according to who maintains the data and how structured it is. Inline lists are best while the data set is small; move to a file when it grows or when non-developers need to edit it.

SourceBest forPython toolsWatch out for
Inline listSmall sets maintained by developersparametrizeBecomes unreadable beyond a screenful
CSVFlat tables, large volumes, easy diffs in Gitcsv.DictReader, pandasEverything is read as text: convert types explicitly
JSONNested data such as API payloadsjson.loadKeep one clear schema per file
ExcelData maintained by business teamsopenpyxl, pandasBinary file: hard to review; lock the column layout
DatabaseData that must reflect the environment's real statesqlite3, psycopg2, SQLAlchemyTests depend on the state of a shared system

How do you load a CSV or JSON file into pytest?

Read the file at collection time, convert each row into a tuple or pytest.param, and pass the resulting list to parametrize.

  1. Store the file next to the tests, for example in tests/data/discounts.csv, and version it in Git with the code.
  2. Write a small loader function that opens the file with csv.DictReader or json.load and converts each value to the right type.
  3. Give each row an identifier column and use it as the test id.
  4. Call the loader in the decorator: @pytest.mark.parametrize("case", load_cases("discounts.csv"), ids=lambda c: c["id"]).
  5. Fail loudly if the file is empty or a column is missing, so a broken data file never results in zero tests passing silently.

Does data-driven testing work for API and Playwright tests?

Yes. For API tests, parameterise the payload and the expected status code, and run each row through requests or the HTTP client of your framework; our API testing tools comparison shows which client fits your stack. In Playwright Test (TypeScript), the documented approach is to loop over an array of data and declare one test() per item, each with a unique title. In pytest-playwright, parametrize works exactly as with any other pytest test.

How do you manage test data safely?

Keep every test independent, generate what you can and never copy personal data from production.

  • Isolation: each row creates what it needs; use pytest fixtures with yield to set up and clean up
  • Synthetic data: libraries such as Faker generate realistic names, addresses and emails without exposing real customers
  • Edge cases: include empty strings, null values, negative numbers, very long inputs and special characters
  • Ownership: every data file has an owner and changes go through code review

When the data comes from pipelines rather than from test files, you also need checks on the data itself; see our guide to data quality testing and validation.

How many data rows do you need?

Fewer than you think: one row per equivalence class plus the values at each boundary. Equivalence partitioning groups inputs that the system should treat the same way; boundary value analysis tests the values at the edges of each group, where bugs cluster. Both techniques are part of the ISTQB Foundation Level syllabus. For a discount valid from 1 to 50 items, test 0, 1, 50 and 51 rather than twenty random quantities.

Is data-driven testing the same as keyword-driven testing?

No. Data-driven testing varies the data while the steps stay fixed; keyword-driven testing describes the steps themselves as reusable keywords, as in Robot Framework. Behaviour-driven development (BDD) tools such as Cucumber or pytest-bdd support both ideas: "Scenario Outline" with an "Examples" table is data-driven testing written in Gherkin.

Frequently asked questions

What is data-driven testing in simple terms?

It is running the same automated test several times with different input data and expected results, stored separately from the test code. Adding a test case means adding a row of data, not writing a new test.

How do you parameterise a test in pytest?

Use the @pytest.mark.parametrize decorator with the argument names and a list of value tuples. pytest generates one independent test per tuple and reports each one separately.

Should test data be stored in CSV or JSON?

Use CSV for flat, tabular data and large volumes, and JSON for nested structures such as API payloads. Both are text files that can be versioned and reviewed in Git alongside the tests.

Can I use production data for data-driven tests?

Avoid it. Production data often contains personal information and changes over time, which makes tests unpredictable. Generate synthetic data with a library such as Faker, or use anonymised extracts.

What is the difference between data-driven and keyword-driven testing?

Data-driven testing keeps the steps fixed and varies the data. Keyword-driven testing expresses the steps themselves as reusable keywords, as in Robot Framework. Many frameworks combine the two.

Learn data-driven testing with Python

At Automation DataCamp (ADC), the Data-Driven Testing with Python course (50 h, online) covers advanced Python for testing, CSV, Excel and JSON data management, database integration and framework patterns, and ends with a complete project.

View the DDT course View the 3-month programme

Related articles