test_debugging.py
Overview
`test_debugging.py` is a comprehensive test suite designed to validate the debugging capabilities integrated into the pytest testing framework. It focuses on testing the behavior and interaction of pytest's built-in debugger support (`--pdb` option), custom debugger classes, breakpoint management, and trace options.
The file contains numerous pytest-based tests that simulate various debugging scenarios, including post-mortem debugging on test failures, interaction with unittest, capturing of stdout/stderr and logs during debugging, recursive debugging sessions, custom debugger class integration, and breakpoint hook configuration.
This test suite also verifies the robustness of debugging features across different Python versions, ensures proper environment management, and validates the interaction between pytest's debugging hooks and other pytest components.
Detailed Documentation
Fixtures
pdb_env(request)
Type:
pytest.fixture(autouse=True)Purpose: Automatically disables pdb++ hijacking when running inner tests via the
pytesterfixture to avoid interference.Parameters:
request: pytest request object for inspecting the current test context.
Usage: Automatically applied; no direct invocation needed.
custom_pdb_calls()
Type:
pytest.fixturePurpose: Provides a dummy custom PDB class (
_CustomPdb) that tracks calls to key debugger methods (init,reset,interaction).Returns:
list[str]— list of method call names recorded.Implementation Detail: Installs
_CustomPdbinto the_pytestnamespace to simulate a custom debugger used in tests.Example:
def test_custom_pdb_usage(custom_pdb_calls):
# After running tests that use --pdbcls=_pytest:_CustomPdb
assert "init" in custom_pdb_calls
custom_debugger_hook()
Type:
pytest.fixturePurpose: Provides a dummy custom debugger class (
_CustomDebugger) that tracks calls toinit,reset,interaction, andset_trace.Returns:
list[str]— list of method call names recorded.Implementation Detail: The fixture dynamically installs and removes the class in
_pytestnamespace.Example:
def test_custom_debugger(custom_debugger_hook):
# Run tests with --pdbcls=_pytest:_CustomDebugger
assert "set_trace" in custom_debugger_hook
Functions
runpdb(pytester: Pytester, source: str) -> RunResult
Purpose: Helper function to create a Python test file from
sourceand run pytest with the--pdboption enabled.Parameters:
pytester(Pytester): pytest's test runner utility fixture.source(str): Python source code string representing the test file.
Returns: The result of
pytester.runpytest_inprocess.Usage Example:
result = runpdb(pytester, "def test_func(): assert False")
runpdb_and_get_stdout(pytester: Pytester, source: str) -> str
Purpose: Runs pytest with
--pdbon the given source and returns the captured stdout as a string.Parameters: Same as
runpdb.Returns:
str— the standard output from the test run.Usage Example:
output = runpdb_and_get_stdout(pytester, "def test_func(): assert False")
print(output)
runpdb_and_get_report(pytester: Pytester, source: str) -> TestReport
Purpose: Runs pytest with
--pdband returns the test report for the "call" phase.Parameters: Same as
runpdb.Returns: The pytest
TestReportobject for the call phase of the test.Important: Asserts that exactly three reports are generated (setup, call, teardown).
Usage Example:
report = runpdb_and_get_report(pytester, "def test_func(): assert False")
assert report.failed
Classes
TestPDB
Purpose: Contains tests for pytest's PDB integration, including post-mortem debugging, interaction with unittest framework, output capturing during debugging, recursive debugging, doctest debugging, and custom PDB classes.
Key Methods:
pdblist(self, request)(fixture): Patches thepost_mortemmethod to collect arguments passed to the debugger.test_pdb_on_fail(self, pytester, pdblist): Tests that PDB is invoked on test failure.test_pdb_on_xfail(self, pytester, pdblist): Tests that PDB does not invoke on xfail.test_pdb_on_skip(self, pytester, pdblist): Tests that PDB does not invoke on skipped tests.test_pdb_unittest_postmortem(self, pytester): Tests PDB integration with unittest post-mortem debugging.test_pdb_print_captured_stdout_and_stderr(self, pytester): Checks that captured output is shown in PDB session.test_pdb_set_trace_kwargs(self, pytester): Tests thatpytest.set_trace()respects kwargs likeheader.test_pdb_custom_cls(self, pytester, custom_pdb_calls): Tests usage of a custom PDB class.test_pdb_validate_usepdb_cls(self): Tests validation of--pdbclsargument format.Other tests cover edge cases like recursive debugging, fixture capturing suspension, interaction on collection errors, and exception chains.
Usage Example:
pytest test_debugging.py::TestPDB::test_pdb_on_fail
TestDebuggingBreakpoints
Purpose: Tests the integration and behavior of Python's
sys.breakpointhookwith pytest's debugging features.Key Tests:
test_sys_breakpointhook_configure_and_unconfigure: Verifies sys.breakpointhook is set and restored correctly.test_pdb_custom_cls: Tests breakpoint interception with a custom debugger.test_environ_custom_class: Tests breakpoint hook configured via environment variable.test_sys_breakpoint_interception: Tests breakpoint invocation triggers PDB session.test_pdb_not_altered: Ensures pdb behavior is unaltered during tests.
TestTraceOption
Purpose: Tests the behavior of the
--traceoption, which sets breakpoints before each test call.Key Tests:
test_trace_sets_breakpoint: Ensures PDB is invoked before each test.test_trace_with_parametrize_handles_shared_fixtureinfo: Verifies that parametrized tests properly expose arguments during trace debugging.
Standalone Tests
test_trace_after_runpytest: Validates that pytest's debugging configuration is reentrant across nested pytest runs.test_quit_with_swallowed_SystemExit: Ensures quitting from PDB does not affect test outcomes improperly.test_pdb_suspends_fixture_capturing: Checks that fixture capturing (capfd,capsys) is suspended and resumed properly during PDB.test_pdbcls_via_local_module: Tests that custom PDB classes specified via--pdbclsare imported correctly and that invalid imports produce errors.test_raises_bdbquit_with_eoferror: Tests handling of EOFError during debugger input.test_pdb_wrapper_class_is_reused: Verifies that the debugger wrapper class is reused across multipleset_tracecalls.
Important Implementation Details
Custom Debugger Injection: The fixtures
custom_pdb_callsandcustom_debugger_hookdynamically insert dummy debugger classes into the_pytestnamespace to simulate custom debugger behavior for testing.Monkeypatching & Environment Control: Many tests use
pytesterandmonkeypatchfixtures to manipulate environment variables, replace functions, and control the test environment to simulate various conditions.Child Process Interaction: Tests that require interactive debugger sessions spawn pytest subprocesses and interact with their input/output streams to simulate real debugging interactions (e.g., sending commands, reading prompts).
Version-Specific Behavior: Some tests account for differences between Python versions (e.g., Python 3.13+ introduces exception chain navigation).
Capturing Suspension: Tests validate that output capturing is correctly suspended when entering PDB sessions and resumed upon continuing.
Recursive Debugging: Tests ensure that recursive debugger invocations (e.g.,
do_debugcallingset_trace) are handled gracefully without deadlocks or exceptions.
Interaction with Other System Components
Pytester Plugin: This test file extensively uses the
pytesterplugin, which provides an API to create test files dynamically, run pytest in subprocesses or in-process, and spawn interactive pytest sessions._pytest.debugging: The file tests components from the
_pytest.debuggingmodule, including thepytestPDBclass and related debugging hooks._pytest._code.Traceback: Used to inspect traceback details in tests, especially for validating correct frame capture during failures.
pytest Hooks: Tests verify the behavior of pytest hooks related to entering and leaving PDB (
pytest_enter_pdb,pytest_leave_pdb).System Breakpoint Hook: The file tests how pytest configures and restores
sys.breakpointhookto integrate Python's built-inbreakpoint()with pytest's debugger.
Visual Diagram: Class Diagram of Main Test Classes
classDiagram
class TestPDB {
+pdblist(request)
+test_pdb_on_fail(pytester, pdblist)
+test_pdb_on_xfail(pytester, pdblist)
+test_pdb_on_skip(pytester, pdblist)
+test_pdb_unittest_postmortem(pytester)
+test_pdb_print_captured_stdout_and_stderr(pytester)
+test_pdb_set_trace_kwargs(pytester)
+test_pdb_custom_cls(pytester, custom_pdb_calls)
+... (many more test methods)
}
class TestDebuggingBreakpoints {
+test_sys_breakpointhook_configure_and_unconfigure(pytester, arg)
+test_pdb_custom_cls(pytester, custom_debugger_hook, monkeypatch)
+test_environ_custom_class(pytester, custom_debugger_hook, arg)
+test_sys_breakpoint_interception(pytester, monkeypatch)
+test_pdb_not_altered(pytester)
}
class TestTraceOption {
+test_trace_sets_breakpoint(pytester)
+test_trace_with_parametrize_handles_shared_fixtureinfo(pytester)
}
Summary
`test_debugging.py` serves as a vital integration and functional test suite verifying pytest's debugger integration features comprehensively. It tests standard and edge cases of PDB invocation, custom debugger class integration, breakpoint hook management, and debugger interaction during various test phases and failure modes. The tests ensure that pytest’s debugging capabilities behave reliably and predictably across Python versions and complex scenarios, maintaining pytest’s robustness as a testing framework with deep debugging support.