Fundamentals 7 min read

Advanced pytest Techniques: Parameterization, Fixtures, Plugins, and More

This article presents a comprehensive guide to pytest, covering parameterized tests, reusable fixtures, dynamic test generation, plugin extensions for coverage and HTML reports, logging capture, nested tests, test ordering, module‑level fixtures, exception handling, parallel execution, mocking, dynamic registration, custom command‑line options, and test insertion for debugging.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Advanced pytest Techniques: Parameterization, Fixtures, Plugins, and More

1. Parameterized Testing pytest supports the pytest.mark.parametrize decorator to run a test function with multiple input sets, reducing duplicate code.

import pytest

def add(x, y):
    return x + y

@pytest.mark.parametrize("x, y, expected", [
    (1, 2, 3),
    (5, -1, 4),
    (0, 0, 0),
])
def test_add(x, y, expected):
    assert add(x, y) == expected

2. Fixtures Fixtures provide reusable test resources such as data, database connections, or mocks.

import pytest

@pytest.fixture
def sample_data():
    return [1, 2, 3]

def test_sample_data(sample_data):
    assert len(sample_data) == 3

3. Dynamic Test Generation Use pytest.mark.parametrize with a range or custom logic to create tests on the fly.

import pytest

@pytest.mark.parametrize("i", range(5))
def test_dynamic(i):
    assert i < 5

4. Plugin Extensions pytest can be extended with plugins such as pytest-cov for coverage and pytest-xdist for parallel execution.

pip install pytest-cov
pytest --cov=my_module

5. Custom HTML Reports Install pytest-html to generate HTML test reports.

pip install pytest-html
pytest --html=report.html

6. Capturing Logs Enable log capture to aid debugging.

import logging, pytest
logging.basicConfig(level=logging.DEBUG)

def test_logging():
    logging.info("This is an info message")
    assert True

Run with pytest -s to display logs.

7. Nested Tests Organize tests using inner classes (available since pytest 3.6).

import pytest

def test_nested():
    class TestInner:
        def test_inner(self):
            assert True

8. Skipping and Expected Failures Use @pytest.mark.skip and @pytest.mark.xfail to mark tests.

import pytest

@pytest.mark.skip(reason="not implemented yet")
def test_not_implemented():
    assert False

@pytest.mark.xfail(reason="known bug")
def test_known_bug():
    assert 1 == 2

9. Test Ordering Control execution order with plugins like pytest-ordering .

pip install pytest-ordering

def test_a():
    assert True

def test_b():
    assert True

def test_c():
    assert True
# Run with: pytest --order=test_a,test_b,test_c

10. Module‑ and Package‑Level Fixtures Define fixtures with scope='module' or scope='package' for shared resources.

# conftest.py
import pytest

@pytest.fixture(scope='module')
def module_level_fixture():
    # setup
    yield
    # teardown

@pytest.fixture(scope='package')
def package_level_fixture():
    # setup
    yield
    # teardown

11. Exception Capturing Verify expected exceptions using pytest.raises .

import pytest

def test_exception_raised():
    with pytest.raises(ValueError):
        int('a')

12. Parallel Test Execution Use pytest-xdist to run tests concurrently.

pip install pytest-xdist
pytest -n 4  # use 4 processes

13. Mocking and Stubbing Leverage unittest.mock or pytest-mock to replace objects during tests.

pip install pytest-mock
import pytest
from unittest.mock import MagicMock

def test_with_mock(mocker):
    mocked_func = mocker.patch('my_module.some_function', return_value=True)
    assert my_module.some_function() is True

14. Dynamic Test Registration Register new test functions at runtime.

import pytest, sys

def register_test(test_name, test_func):
    setattr(sys.modules[__name__], test_name, test_func)

def test_a_passes():
    assert True

register_test('test_a_passes', test_a_passes)

15. Custom Command‑Line Options Add custom CLI flags via pytest_addoption .

import pytest

def pytest_addoption(parser):
    parser.addoption('--config', action='store', default='default.conf')

def pytest_configure(config):
    print(f"Using config file: {config.getoption('--config')}")

16. Test Insertion for Debugging Insert breakpoints during test runs.

import pytest

def test_insertion():
    pytest.set_trace()
    assert True
TestingPluginspytestfixtures
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.