Skip to content
CodeKruPro

Framework · Python

Test data and configuration

Data-driven tests, configuration files and environments.

Learn: Test data and configuration in a pytest framework8 minute read

Test data is the input a test uses, such as user names, products and expected messages. Configuration is everything that changes between runs, such as the base URL, the browser and timeouts. Interviewers ask how your tests get their data, how you switch between environments (separate copies of the app, such as qa for testers and staging for last checks before release) and where secrets are kept. In pytest the answers are short: data files feed parametrize, a session fixture loads the configuration, and command-line options choose the environment.

Data-driven tests

"Data-driven" means the steps stay the same and only the data changes. With parametrize, each row of data becomes its own test with its own result:

A CSV file with three rows is passed to pytest parametrize, so test_login becomes three tests named by row, with two passes and one failure.
parametrize turns each row into a separate test with a readable id.
import csv
import json
import pathlib
import pytest

DATA = pathlib.Path(__file__).parent / "data"

def csv_rows(name):
    with (DATA / name).open(newline="", encoding="utf-8") as f:
        return list(csv.DictReader(f))

LOGINS = csv_rows("logins.csv")

@pytest.mark.parametrize("row", LOGINS, ids=[r["case"] for r in LOGINS])
def test_login(login_page, row):
    login_page.login_as(row["user"], row["password"])
    assert login_page.message() == row["expected"]

csv.DictReader returns each row as a dictionary from column name to value. Every value is a string (text), so convert numbers yourself. JSON keeps numbers and true/false values: json.loads((DATA / "users.json").read_text()). For Excel, the openpyxl library (installed separately) reads sheets, for example with load_workbook(path).active.iter_rows(min_row=2, values_only=True). CSV and JSON show clear changes in Git and need no extra library, so prefer them unless business people maintain Excel files.

A case column used as the id makes reports readable: test_login[locked-account] says far more than test_login[row3].

Configuration per environment

Keep URLs, timeouts and flags out of the code. Use one file per environment and a session fixture that loads it:

# conftest.py
import json, os, pathlib, pytest

CONFIG_DIR = pathlib.Path(__file__).parent / "config"

def pytest_addoption(parser):
    parser.addoption("--env", default="qa")
    parser.addoption("--browser", default="chrome")

@pytest.fixture(scope="session")
def config(request):
    env = request.config.getoption("--env")
    data = json.loads((CONFIG_DIR / f"{env}.json").read_text())
    data["browser"] = request.config.getoption("--browser")
    return data

Now pytest --env=staging --browser=firefox switches both. pytest_addoption belongs in the root conftest.py. pytest rejects options it does not know, so every custom option must be declared there. Environment variables (named values set outside your program, in the shell or CI) are the other common source. CI means a server that runs your tests automatically, for example after every code change.

Secrets

Passwords and API keys never live in the repository. CI keeps them as secrets and passes them to the job as environment variables:

password = os.environ.get("TEST_USER_PASSWORD")
if not password:
    pytest.exit("TEST_USER_PASSWORD is not set", returncode=2)

Locally, developers set the variable in their shell or in a file that Git ignores (one listed in .gitignore). Hide secrets in logs and reports.

Managing data across runs

  • Reference data that rarely changes sits in files in version control.
  • Accounts per environment sit next to the environment config, with passwords from CI.
  • Data a test changes is created by the test, through an API (a way for code to talk to the app's server) in a fixture, with unique values, and removed in the fixture's teardown.
import uuid

@pytest.fixture
def new_user(api):
    user = api.create_user(email=f"user_{uuid.uuid4().hex[:8]}@test.example")
    yield user
    api.delete_user(user["id"])

Data classes with defaults (@dataclass) or small factory functions let a test set only the fields it cares about. For files, the built-in tmp_path fixture gives each test its own empty folder, which suits downloads.

Independence

A test must pass alone, in any order and in parallel. With pytest-xdist (the plugin that runs tests in parallel) each worker is a separate process, so Python variables are never shared, but accounts and database rows still are. Unique data per test keeps parallel runs safe.

How to answer in an interview

When asked how you manage test data, name the three kinds (reference data, accounts per environment, data each test creates) and say where each lives. Give one example of a fixture that creates and removes its own data. Then cover secrets and switching environments in one sentence each.

Common mistakes

  • Forgetting that CSV values are text, then comparing "30" with 30.
  • Reading sys.argv for custom options instead of declaring them with pytest_addoption.
  • Committing a password in a JSON config file.
  • One test relying on data another test created. pytest has no built-in test dependencies, which is a hint to move that step into a fixture.

Recap

parametrize turns each data row into its own test. A session fixture loads one config file per environment, chosen with a --env option. Secrets come from CI environment variables. Fixtures create the data a test changes and remove it in teardown, so every test stands alone.

8 questions0/8 solved

StatusQuestionDifficultyAsked in
Not startedRead test data from a file and drive tests with it (Python)MediumAsked in: Accenture, Capgemini, Infosys +4
Not startedChoose browser and environment from the pytest command lineMediumAsked in: Accenture, Cognizant, TCS +1
Pro+Configuration for several environments (Python)MediumAsked in: Cognizant, TCS, Wipro
Pro+Manage and generate test data across runs and environmentsMediumAsked in: Capgemini
Pro+What csv.DictReader gives you for test dataEasy-MediumAsked in: Accenture, Capgemini, Infosys +4
Pro+Unique test data for every runEasy-MediumAsked in: Capgemini
Pro+Avoid shared state: keep every test independentMediumAsked in: Happiest Minds, Honeywell
Pro+Where do test passwords and API keys belong?EasyAsked in: Cognizant, TCS, Wipro
Not startedNot startedIn progressIn progressSolvedSolvedPro+Pro+

The first 2 questions of each topic are free. Pro+ opens every question.

Back to the plan