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.
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) == expected2. 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) == 33. 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 < 54. 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_module5. Custom HTML Reports Install pytest-html to generate HTML test reports.
pip install pytest-html
pytest --html=report.html6. 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 TrueRun 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 True8. 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 == 29. 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_c10. 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
# teardown11. 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 processes13. 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 True14. 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 TrueTest Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.