python-testing · laurigates — Claude Code skill: what it does, how to install
Guides agents through writing pytest suites, setting up fixtures, mocks, and test coverage. Useful for TDD workflows in Python projects.
npx skills add laurigates/claude-plugins --skill python-testing -a claude-codeWhat python-testing does
The skill provides reference workflows for writing Python unit and integration tests using pytest. It instructs the agent on running tests via uv run pytest, measuring line coverage with pytest-cov, and isolating external dependencies with unittest.mock or pytest-mock. The agent inspects files and executes commands using Bash, Read, Grep, and Glob tools.
Included snippets cover test parametrization, @pytest.mark.asyncio, temporary files with tmp_path, and pyproject.toml options. It is not invoked via a slash command. Instead, it activates automatically whenever testing or pytest is mentioned.
For multi-package fixture hierarchies or parallel execution with pytest-xdist, this skill falls short; the author suggests pytest-advanced instead.
What it helps with
- write pytest test suites with parameter sets and fixtures
- configure coverage reports using pytest-cov and uv
- mock external API calls with unittest.mock or pytest-mock
- test asynchronous functions and verify raised exceptions
Example prompts for the agent
- Write pytest unit tests for auth.py covering edge cases and exceptions
- Create a database fixture in conftest.py and mock the payment gateway
- Run the test suite using uv with terminal coverage reporting
How to install python-testing
1Skills CLI (Vercel)
npx skills add laurigates/claude-plugins --skill python-testing -a claude-code2Manually: put the files in place
~/.claude/skills/python-testing/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/python-testing/
1Skills CLI (Vercel)
npx skills add laurigates/claude-plugins --skill python-testing -a codex2Manually: put the files in place
.agents/skills/python-testing/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add laurigates/claude-plugins --skill python-testing -a cursor2Manually: put the files in place
.cursor/skills/python-testing/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install laurigates/claude-plugins python-testing2Manually: put the files in place
.github/skills/python-testing/SKILL.md1Skills CLI (Vercel)
npx skills add laurigates/claude-plugins --skill python-testing -a gemini-cli2Platform CLI
gemini skills install https://github.com/laurigates/claude-plugins --path python-plugin/skills/python-testingManually: put the files in place
.devin/skills/python-testing/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add laurigates/claude-plugins --skill python-testing -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about python-testing
How to install python-testing in Claude Code?
Run npx skills add laurigates/claude-plugins --skill python-testing -a claude-code in your terminal. The file is placed at ~/.claude/skills/python-testing/SKILL.md.
What does python-testing do?
It provides your coding agent with best practices for pytest, mocking external services, async test setups, and TDD red-green-refactor cycles.
When should pytest-advanced be used instead of python-testing?
Use pytest-advanced when configuring pytest-xdist parallel runs, writing custom hookimpl plugins, or sharing fixture libraries across packages.
Source text
SKILL.md · MIT
---
created: 2025-12-16
modified: 2026-05-09
reviewed: 2026-04-25
name: python-testing
description: Python testing with pytest, coverage, fixtures, and mocking. Use when the user mentions pytest, unit tests, coverage, fixtures, mocking, or writing Python tests.
user-invocable: false
allowed-tools: Bash, Read, Grep, Glob
---
# Python Testing
Quick reference for Python testing with pytest, coverage, fixtures, and best practices.
## When to Use This Skill
| Use this skill when... | Use pytest-advanced instead when... |
|---|---|
| Writing first pytest tests, learning fixtures and parametrization basics | Designing reusable conftest.py fixture hierarchies or parallel-execution markers |
| Setting up coverage reporting and basic mocking with `unittest.mock` | Tuning pytest-xdist, custom markers, or hookimpl plugins |
| Following TDD red-green-refactor cycles on a single module | Building shared fixture libraries across a multi-package test suite |
## When This Skill Applies
- Writing unit tests and integration tests
- Test-driven development (TDD)
- Test fixtures and parametrization
- Coverage analysis
- Mocking and patching
- Async testing
## Quick Reference
### Running Tests
```bash
# Basic test run
uv run pytest
# Verbose output
uv run pytest -v
# Show print statements
uv run pytest -s
# Stop at first failure
uv run pytest -x
# Run specific test
uv run pytest tests/test_module.py::test_function
# Run by keyword
uv run pytest -k "test_user"
```
### Test Coverage
```bash
# Run with coverage
uv run pytest --cov
# HTML report
uv run pytest --cov --cov-report=html
# Show missing lines
uv run pytest --cov --cov-report=term-missing
# Coverage for specific module
uv run pytest --cov=mymodule tests/
```
### Fixtures
```python
import pytest
@pytest.fixture
def sample_data():
return {"key": "value"}
@pytest.fixture(scope="module")
def db_connection():
conn = create_connection()
yield conn
conn.close()
def test_with_fixture(sample_data):
assert sample_data["key"] == "value"
```
### Parametrize Tests
```python
import pytest
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("world", "WORLD"),
("test", "TEST"),
])
def test_uppercase(input: str, expected: str):
assert input.upper() == expected
@pytest.mark.parametrize("value,is_valid", [
(1, True),
(0, False),
(-1, False),
])
def test_validation(value, is_valid):
assert validate(value) == is_valid
```
### Markers
```python
import pytest
@pytest.mark.slow
def test_slow_operation():
# Long-running test
pass
@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
pass
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_specific():
pass
@pytest.mark.xfail
def test_known_issue():
# Expected to fail
pass
```
```bash
# Run only marked tests
uv run pytest -m slow
uv run pytest -m "not slow"
```
### Async Testing
```python
import pytest
@pytest.mark.asyncio
async def test_async_function():
result = await async_operation()
assert result == expected_value
@pytest.fixture
async def async_client():
client = AsyncClient()
await client.connect()
yield client
await client.disconnect()
```
### Mocking
```python
from unittest.mock import Mock, patch, MagicMock
def test_with_mock():
mock_obj = Mock()
mock_obj.method.return_value = "mocked"
assert mock_obj.method() == "mocked"
@patch('module.external_api')
def test_with_patch(mock_api):
mock_api.return_value = {"status": "success"}
result = call_external_api()
assert result["status"] == "success"
# pytest-mock (cleaner)
def test_with_mocker(mocker):
mock = mocker.patch('module.function')
mock.return_value = 42
assert function() == 42
```
## Test Organization
```
project/
├── src/
│ └── myproject/
│ ├── __init__.py
│ └── module.py
└── tests/
├── __init__.py
├── conftest.py # Shared fixtures
├── test_module.py
└── integration/
└── test_api.py
```
## conftest.py
```python
# tests/conftest.py
import pytest
@pytest.fixture(scope="session")
def app_config():
return {"debug": True, "testing": True}
@pytest.fixture(autouse=True)
def reset_db():
setup_database()
yield
teardown_database()
```
## pyproject.toml Configuration
```toml
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"-v",
"--strict-markers",
"--cov=src",
"--cov-report=term-missing",
]
markers = [
"slow: marks tests as slow",
"integration: marks tests as integration tests",
]
[tool.coverage.run]
source = ["src"]
omit = ["*/tests/*", "*/test_*.py"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
]
```
## Common Testing Patterns
### Test Exceptions
```python
import pytest
def test_raises_exception():
with pytest.raises(ValueError):
function_that_raises()
def test_raises_with_message():
with pytest.raises(ValueError, match="Invalid input"):
function_that_raises()
```
### Test Warnings
```python
import pytest
def test_deprecation_warning():
with pytest.warns(DeprecationWarning):
deprecated_function()
```
### Temporary Files
```python
def test_with_tmp_path(tmp_path):
file_path = tmp_path / "test.txt"
file_path.write_text("content")
assert file_path.read_text() == "content"
```
## TDD Workflow
```bash
# 1. RED: Write failing test
uv run pytest tests/test_new_feature.py
# FAILED
# 2. GREEN: Implement minimal code
uv run pytest tests/test_new_feature.py
# PASSED
# 3. REFACTOR: Improve code
uv run pytest # All tests pass
```
## See Also
- `uv-project-management` - Adding pytest to projects
- `python-code-quality` - Combining tests with linting
- `python-development` - Core Python development patterns
## References
- Official docs: https://docs.pytest.org/
- Detailed guide: See REFERENCE.md in this skill directory
© laurigates · MIT · laurigates/claude-plugins
Similar skills
All skills for Testing and QA →python-testing by other authors comes first.