PyTest Quick Reference
Fixtures · Markers · Hooks · Parametrization · Parallel Execution
Naming Conventions
PyTest auto-discovers tests only when they follow these exact naming rules.
| Entity | Convention |
|---|---|
| File / Module | Case insensitive — must match test_*.py or *_test.py |
| Class Name | Must start with exactly Test |
| Method Name | Must start with exactly test |
PyTest scans directories recursively for files matching the pattern. No registration needed — just follow the naming rules.
Execution Methods
Run entire directories, single modules, or filter by markers. Flags control verbosity and parallelism.
pytest -s -v .\API-Automation\Execute all modules in the directorypytest -s -v .\API-Automation\pytest_test.pyExecute one specific module
| Flag | Purpose |
|---|---|
| -s | Show print() statements from test methods |
| -v | Provide detailed / verbose output |
| -rs | Show details for skipped test cases |
| -p no:warnings | Suppress all warnings |
| -n=3 | Run 3 test cases in parallel (requires pytest-xdist) |
Fixture Functions
Fixtures provide setup and teardown logic. The yield keyword splits setup (before) from teardown (after).
import pytest @pytest.fixture(autouse=True, scope="module") def fixture_function(): print() print("Setup Method") # runs before tests yield # ← setup | teardown boundary print() print("Teardown Method") # runs after tests
yield boundaryAll statements before yield act as setup and run at the start of the defined scope. All statements after yield act as teardown and run at the end of the scope.
@pytest.fixture(autouse=True) — when used, the fixture will be applied automatically to every test without manually passing it as an argument.
Fixture Scope
Controls how often a fixture is set up and torn down. Use broader scopes to avoid repeated expensive operations.
| Scope | Lifecycle |
|---|---|
| function | Default — runs before and after every test case |
| class | Runs once before the class; tears down after all class tests complete |
| module | Runs once before the module; tears down after all module tests complete |
| package | Runs once per package directory |
| session | Runs once per entire test session |
@pytest.fixture(scope="class") def db_connection(): conn = create_connection() yield conn conn.close()
conftest.py
A special file that holds shared fixtures available across multiple modules.
conftest.py
Fixtures defined here are available to all functions, classes, and modules in the same directory and below.
Module-level fixture
Fixtures defined inside a regular module (test_*.py) can only be used within that specific file.
Place conftest.py at the root of your test directory for project-wide fixtures, or in sub-directories for scoped sharing.
Markers
Markers control test behavior: skipping, grouping, ordering, dependencies, and parametrization.
Custom markers must be registered in pytest.ini to suppress unknown-marker warnings. Add them under [pytest] markers =.
[pytest]
markers =
sanity
regression
zem
ask
Skipping & XFail
Three ways to skip tests, plus a marker for expected failures.
| Decorator / Call | Behavior |
|---|---|
| @pytest.mark.skip(reason=…) | Unconditionally skip — always skipped regardless of environment |
| @pytest.mark.skipif(condition, reason=…) | Skip only when the given condition evaluates to True |
| pytest.skip() | Skip programmatically at runtime inside a test or fixture |
| @pytest.mark.xfail(reason=…) | Mark a test as expected to fail — highlighted specially in reports |
import pytest import sys @pytest.fixture def usersession(): session_active = False if not session_active: pytest.skip("User Session is not active") class Test: @pytest.mark.skipif(sys.platform == "win32", reason="Not applicable for Windows") def test_Method1(self): print("Method One") def test_Method2(self, usersession): print("Method Two")
Use -rs flag when running pytest to see the skip reasons in the output summary.
Ordering
Control test execution order using the pytest-ordering package. Register custom markers in pytest.ini.
Install with: pip install pytest-ordering
@pytest.mark.run(order=1) def test_first(): ... @pytest.mark.first def test_also_first(): ...
Dependency — use pytest-dependency to make a test depend on another passing first.
@pytest.mark.dependency(depends=["Test::test_launch"]) — format is ClassName::TestMethod.
Grouping with Markers
Tag tests with custom markers and run only specific groups using -m.
@pytest.mark.sanity def test_login(): ... @pytest.mark.regression def test_checkout(): ...
pytest -m "sanity and regression" .\API-Automation\Run tests that have both tagspytest -m "sanity or regression" .\API-Automation\Run tests that have either tagpytest -s -v -m "not sanity" .\API-Automation\Run all tests except sanity-tagged ones
Parallel Execution
Run multiple tests simultaneously using pytest-xdist to significantly cut down total suite time.
Install with: pip install pytest-xdist
pytest -s -v -n=2 .\API-Automation\Run 2 test cases in parallelpytest -s -v -n=auto .\API-Automation\Auto-detect CPU count and use all cores
Tests running in parallel must be independent — no shared state or order-dependent logic. Fixtures with scope="session" may behave differently under -n.
Parametrization
Used for data-driven testing when input quantity is small. Each parameter set becomes a separate test run.
import pytest class Test: @pytest.mark.parametrize('num1, num2, sum', [(1, 1, 2), (2, 3, 5)]) def test_addition(self, num1, num2, sum): assert num1 + num2 == sum def test_sum(self, num1, num2, sum): assert num1 + num2 == sum
For larger datasets, consider using CSV/JSON files with a fixture that reads and yields data, keeping the test method clean.
Hooks
Hooks let you capture command-line arguments and inject environment metadata into HTML reports.
import pytest def pytest_addoption(parser): parser.addoption( '--browser', action='store', default="edge", help="Browser to run test" ) @pytest.fixture def browser(request): return request.config.getoption("--browser")
pytest -s -v .\API-Automation\ --browser=chromePass browser value from command line
import pytest from pytest_metadata.plugin import metadata_key def pytest_addoption(parser): parser.addoption('--browser', action='store', default="edge", help="Browser to run test") @pytest.fixture def browser(request): return request.config.getoption("--browser") @pytest.mark.optionalhooks def pytest_metadata(metadata): metadata.pop("Python", None) @pytest.mark.optionalhooks def pytest_configure(config): config.stash[metadata_key]["Project Name"] = "Example"
pytest_metadata and pytest_configure hooks allow you to customize the environment section of HTML reports — great for CI/CD pipelines where you need traceability.