| name | python-pytest-failure-debugging |
| description | Debugs pytest test failures in Python by analyzing error messages, fixing assertions, updating fixtures, and resolving test dependencies. Use when pytest tests fail, test assertions break, fixtures error, or when debugging Python unit tests, integration tests, or parametrized tests. |
| metadata | {"author":"Chisanan232"} |
Python Pytest Failure Debugging Skill
Purpose
This skill provides a systematic approach to debugging pytest test failures quickly and safely, preserving test integrity while fixing the root cause.
When to Invoke This Skill
Use this skill when:
- Pytest tests fail locally during development
- Tests fail in CI but pass locally
- Tests fail intermittently (flaky tests)
- Test fixtures or setup/teardown fail
- Assertion errors occur
- Tests timeout or hang
When NOT to Invoke This Skill
Do not use this skill for:
- Designing new tests (use
test-design skill)
- Coverage issues (use
coverage-regression-repair skill)
- Type checking failures (use
python-mypy-debugging skill)
- Linting failures (use
python-ruff-fixing skill)
Prerequisites
Before debugging pytest failures:
- Consult AGENTS.md: Check test runner configuration and test conventions
- Understand the test: Know what behavior the test is verifying
- Reproduce locally: Ensure you can run the failing test locally
Do Not Assume
- Do NOT assume all Python projects use pytest (check AGENTS.md first)
- Do NOT assume test file naming conventions (check AGENTS.md)
- Do NOT assume fixture locations or patterns
- Do NOT assume the test is wrong (the code might be wrong)
- Do NOT assume you can weaken assertions to make tests pass
- Do NOT assume you can skip or disable failing tests without justification
Pytest Failure Debugging Process
Phase 1: Identify the Failure Type
Read the pytest output and categorize the failure:
Assertion Failures
AssertionError: assert actual == expected
- Value mismatch
- Type mismatch
- Collection comparison failure
- Boolean assertion failure
Exception Failures
test_function raised an unexpected exception
- Unexpected exception during test execution
- Missing exception that should have been raised
- Wrong exception type raised
Fixture Failures
fixture 'my_fixture' not found
ERROR at setup of test_function
- Missing fixture
- Fixture scope issues
- Fixture dependency problems
- Setup/teardown failures
Timeout Failures
test_function timed out after 30 seconds
- Infinite loops
- Blocking I/O
- Deadlocks
Import Failures
ImportError: cannot import name 'X' from 'Y'
ModuleNotFoundError: No module named 'X'
- Missing dependencies
- Circular imports
- Path issues
Phase 2: Gather Context
Before making changes, gather information:
-
Read the full test output
pytest -vv path/to/test_file.py::test_function
pytest -l path/to/test_file.py::test_function
pytest -s path/to/test_file.py::test_function
-
Check test isolation
pytest path/to/test_file.py::test_function
pytest path/to/test_file.py
-
Inspect the test code
- What behavior is being tested?
- What are the assertions checking?
- What fixtures are used?
- What is the test setup?
-
Inspect the implementation code
- What changed recently?
- Does the code match the test expectations?
- Are there edge cases not handled?
Phase 3: Classify the Root Cause
Determine the actual problem:
Test is Correct, Code is Wrong
- Implementation doesn't match specification
- Edge case not handled
- Regression introduced
Action: Fix the implementation code, not the test.
Test is Wrong, Code is Correct
- Test expectations are incorrect
- Test is outdated after intentional behavior change
- Test has wrong assertions
Action: Update the test to match correct behavior. Document why.
Test is Flaky
- Race conditions
- Timing dependencies
- External dependencies (network, filesystem)
- Shared state between tests
Action: Fix test isolation or add proper synchronization.
Environment Issue
- Missing dependencies
- Wrong Python version
- Missing environment variables
- File permissions
Action: Fix environment setup, update documentation.
Phase 4: Apply the Fix
Based on root cause, apply the appropriate fix:
Fixing Implementation Code
-
Identify the minimal fix
- Change only what's necessary
- Preserve existing behavior for other cases
- Don't refactor while fixing bugs
-
Verify the fix
pytest path/to/test_file.py::test_function
pytest path/to/test_file.py
pytest -k "pattern"
-
Check for regressions
pytest path/to/module/
Fixing Test Code
-
Understand why the test is wrong
- Was there an intentional behavior change?
- Was the test always wrong?
- Is this a new edge case?
-
Update test carefully
- Preserve test intent
- Update assertions to match correct behavior
- Add comments explaining the change
-
Verify other tests still pass
pytest path/to/test_file.py
Fixing Flaky Tests
-
Identify the source of flakiness
- Run test multiple times:
pytest --count=10 path/to/test_file.py::test_function
- Check for shared state
- Check for timing assumptions
-
Apply proper fixes
- Use proper fixtures for isolation
- Use mocking for external dependencies
- Add proper waits/polling instead of sleep
- Use pytest-timeout for hanging tests
-
Verify stability
pytest --count=20 path/to/test_file.py::test_function
Fixing Fixture Issues
-
Check fixture scope
function - new instance per test
class - shared within test class
module - shared within module
session - shared across all tests
-
Check fixture dependencies
- Ensure all required fixtures exist
- Check fixture order
- Verify fixture cleanup
-
Fix fixture definition
import pytest
@pytest.fixture(scope="function")
def my_fixture():
resource = create_resource()
yield resource
resource.cleanup()
Phase 5: Validate the Fix
After applying the fix:
-
Run the specific test
pytest path/to/test_file.py::test_function
-
Run related tests
pytest path/to/test_file.py
pytest path/to/module/
-
Check coverage if relevant
pytest --cov=module_under_test path/to/test_file.py
-
Run full suite before committing (if time permits)
pytest
Phase 6: Document and Commit
-
Document the fix
- If test was wrong, explain why in commit message
- If code was wrong, ensure fix is clear
- If flakiness was fixed, document the root cause
-
Commit with clear message
🐛 Fix failing test_user_authentication
- Root cause: Missing null check in User.authenticate()
- Added null check before password comparison
- Test now passes consistently
Or for test fixes:
✅ Update test_calculate_discount expectations
- Behavior changed in #123 to round discounts
- Updated assertions to expect rounded values
- All tests now pass
Common Pytest Patterns
Running Specific Tests
pytest path/to/test_file.py::test_function
pytest path/to/test_file.py::TestClass
pytest path/to/test_file.py::TestClass::test_method
pytest -k "test_user"
pytest -m "slow"
Debugging Options
pytest -v
pytest -vv
pytest -l
pytest -s
pytest -x
pytest --pdb
pytest --durations=10
Fixture Debugging
pytest --setup-show
pytest --fixtures
Safety Guidelines
DO
- ✅ Read the full error message and traceback
- ✅ Reproduce the failure locally before fixing
- ✅ Understand what the test is verifying
- ✅ Fix the root cause, not the symptom
- ✅ Run related tests after fixing
- ✅ Preserve test intent when updating tests
- ✅ Document why tests were changed
DO NOT
- ❌ Weaken assertions to make tests pass
- ❌ Skip or disable tests without justification
- ❌ Change test behavior without understanding why it failed
- ❌ Refactor code while debugging test failures
- ❌ Commit fixes without running related tests
- ❌ Assume the test is wrong (code might be wrong)
- ❌ Fix flaky tests with
time.sleep() (use proper synchronization)
Common Failure Patterns and Solutions
Pattern: "AssertionError: assert None is not None"
Cause: Function returning None instead of expected value
Solution: Check function implementation, ensure return statement exists
Pattern: "fixture 'X' not found"
Cause: Fixture not imported or not in conftest.py
Solution: Move fixture to conftest.py or import it properly
Pattern: "Test passes locally but fails in CI"
Cause: Environment differences, timing issues, or missing dependencies
Solution: Check CI environment, add missing dependencies, fix timing assumptions
Pattern: "Tests fail when run together but pass individually"
Cause: Shared state between tests, improper cleanup
Solution: Use proper fixtures, ensure test isolation, check for global state
Pattern: "ImportError in tests"
Cause: Missing test dependencies, wrong Python path
Solution: Install test dependencies, check PYTHONPATH, verify package installation
Integration with Other Skills
- After fixing tests: Use
coverage-regression-repair if coverage dropped
- If type errors appear: Use
python-mypy-debugging
- If lint errors appear: Use
python-ruff-fixing
- Before committing: Use
code-review-prep to prepare PR
Project-Specific Considerations
Check AGENTS.md for:
- Test runner command (might not be
pytest)
- Test file naming conventions
- Fixture locations
- Test markers and their meanings
- CI test execution strategy
- Coverage requirements
Validation Checklist
Before considering the debugging complete:
Example Debugging Session
$ pytest tests/test_user.py::test_create_user
FAILED tests/test_user.py::test_create_user - AssertionError: assert None == User(...)
$ pytest -vv -l tests/test_user.py::test_create_user
$ cat tests/test_user.py
$ cat src/user.py
$ pytest tests/test_user.py::test_create_user
PASSED
$ pytest tests/test_user.py
PASSED (5 tests)
$ git add src/user.py
$ git commit -m "🐛 Fix create_user missing return statement"
Summary
This skill helps you debug pytest failures systematically by:
- Identifying the failure type
- Gathering context
- Classifying the root cause
- Applying the appropriate fix
- Validating the fix
- Documenting and committing
Always fix the root cause, preserve test intent, and verify related tests still pass.
Source: Chisanan232/ai-development-config — distributed by TomeVault.