python-testing
Write focused, deterministic, well-documented pytest tests for AI-authored code.
SKILL.md.claude/skills/python-testing/SKILL.md
GitHubWhat I do
I help with three pytest workflows:
- Write tests — generate focused, well-documented tests following project conventions
- Check coverage — detect untested lines per file or folder
- Bootstrap setup — install dev dependencies and apply recommended pytest configuration
Supporting files in this skill:
assets/pytest.ini.template— ready-to-copy pytest configurationscripts/analyze_coverage.sh [path]— coverage analysis helper (whole src or specific folder/module)- Run from repo root as:
./.claude/skills/python-testing/scripts/analyze_coverage.sh [path] - Or use repo-root-safe path:
"$(git rev-parse --show-toplevel)/.claude/skills/python-testing/scripts/analyze_coverage.sh" [path]
- Run from repo root as:
When to use me
Use when you want to:
- Write new tests for a module or feature
- Review and improve existing test quality
- Check coverage for a specific file, folder, or the whole project
- Bootstrap pytest for a new project (deps + config)
Example usage
"Write tests for the slugify function in src/utils/text.py"
"Check coverage for src/services/payment.py"
"Set up pytest for this project with coverage and async support"
Conventions
Naming
- Files:
test_<module_or_feature>.py - Functions:
test_<unit>__<behavior>__<condition> - Mark every AI-generated test with
@pytest.mark.ai
Docstring (required on every test)
Three-part format:
Purpose: What this test verifies.
Why this matters: Business or technical consequence if it breaks.
Setup summary: What's arranged and what's asserted.
Structure
- AAA pattern: Arrange – Act – Assert
- No conditionals or loops in test body (use parametrization)
- One responsibility per test
Fixtures
- Centralize in
<domain>_fixtures.py - Register via
pytest_plugins = ["tests.fixtures"]inconftest.py - Return typed objects; modify only what changes per test
Mocking
- Use
mockerfixture (pytest-mock) - Mock at the import boundary of the code under test
- Use
spec=Truefor type safety
Coverage
- Target ≥ 80% for AI-authored tests
./.claude/skills/python-testing/scripts/analyze_coverage.sh— full src coverage./.claude/skills/python-testing/scripts/analyze_coverage.sh src/services— coverage for a specific folder./.claude/skills/python-testing/scripts/analyze_coverage.sh src/utils/text.py— coverage for a single file
Test scope & quality
- Test every public function and method you touched
- Cover happy paths plus negative scenarios, validation failures, and async edge cases
- Keep tests deterministic and isolated (clean up temp data, reset mocks)
- Mock only external dependencies using
pytest-mock'smockeror hand-rolled fixtures - Document why each test matters using the required docstring template
Test cases to include
- Happy path scenarios that reflect realistic inputs
- Edge cases such as empty inputs, boundary values, and timeout paths
- Error handling or exception flows (raise and capture specific exceptions)
- Dependency failures (e.g., network timeouts, missing files) while staying fast
- Concurrency and async behavior when applicable (use
pytest.mark.asyncioor trio)
Test quality checklist
- Tested all public functions and methods touched by the change
- Covered happy path scenarios plus edge cases and negative flows
- Added or updated tests for error handling and exception cases
- Mocked external dependencies appropriately and kept mocks scoped
- Ensured all tests are deterministic and repeatable
- Kept tests focused (one assertion per behavior) and avoided loops/conditionals
- Documented each test with the three-part docstring
- Verified coverage with
scripts/analyze_coverage.shwhen changes affect multiple modules
Setup (new project)
- Install dev dependencies:
- uv:
uv add --dev pytest pytest-cov pytest-asyncio pytest-mock - pip:
pip install pytest pytest-cov pytest-asyncio pytest-mock
- uv:
- Copy
assets/pytest.ini.template→pytest.iniat the project root - Add
tests/directory with an empty__init__.pyandconftest.py