skills/python-testing-patterns/SKILL.md
Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development. Use when writing unit or integration tests, setting up test infrastructure, implementing TDD, testing async code, mocking external dependencies, writing property-based tests, testing database operations, or debugging failing tests. Invoke this skill any time the user wants to write or improve Python tests.
npx skillsauth add rory-data/copilot python-testing-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Master pytest fundamentals through essential patterns and practical examples, from basic unit tests to mocking external dependencies.
# test_example.py
def add(a, b):
return a + b
def test_add():
"""Basic test example."""
result = add(2, 3)
assert result == 5
def test_add_negative():
"""Test with negative numbers."""
assert add(-1, 1) == 0
# Run with: uv run pytest test_example.py
# test_calculator.py
import pytest
class Calculator:
"""Simple calculator for testing."""
def add(self, a: float, b: float) -> float:
return a + b
def divide(self, a: float, b: float) -> float:
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
def test_addition():
"""Test addition."""
calc = Calculator()
assert calc.add(2, 3) == 5
assert calc.add(-1, 1) == 0
def test_division_by_zero():
"""Test division by zero raises error."""
calc = Calculator()
with pytest.raises(ValueError, match="Cannot divide by zero"):
calc.divide(5, 0)
# test_database.py
import pytest
@pytest.fixture
def db():
"""Fixture that provides connected database."""
# Setup
database = {"connected": True}
yield database
# Teardown
database["connected"] = False
def test_database_query(db):
"""Test using fixture."""
assert db["connected"] is True
# test_validation.py
import pytest
@pytest.mark.parametrize("email,expected", [
("[email protected]", True),
("invalid.email", False),
])
def test_email_validation(email, expected):
"""Test email validation with various inputs."""
assert is_valid(email) == expected
# test_api_client.py
import pytest
from unittest.mock import Mock, patch
def test_api_call():
"""Test API call with mock."""
mock_response = Mock()
mock_response.json.return_value = {"id": 1}
with patch("requests.get", return_value=mock_response):
result = get_user(1)
assert result["id"] == 1
# test_exceptions.py
import pytest
def test_exception():
"""Test exception is raised."""
with pytest.raises(ValueError, match="error message"):
divide(10, 0)
For additional testing patterns and advanced techniques, see the reference files:
# tests/
# __init__.py
# conftest.py # Shared fixtures
# test_unit/ # Unit tests
# test_integration/ # Integration tests
# test_e2e/ # End-to-end tests
# Good test names describe what is tested and expected outcome
def test_user_creation_with_valid_data():
pass
def test_login_fails_with_invalid_password():
pass
# Bad test names
def test_1(): # Not descriptive
pass
def test_user(): # Too vague
pass
import pytest
@pytest.mark.slow
def test_slow_operation():
pass
@pytest.mark.integration
def test_database_integration():
pass
# Run with:
# uv run pytest -m slow # Run only slow tests
# uv run pytest -m "not slow" # Skip slow tests
tools
Queries, manages, and troubleshoots Apache Airflow using the af CLI. Covers listing DAGs, triggering runs, reading task logs, diagnosing failures, debugging DAG import errors, checking connections, variables, pools, and monitoring health. Also routes to sub-skills for writing DAGs, debugging, deploying, and migrating Airflow 2 to 3. Use when user mentions "Airflow", "DAG", "DAG run", "task log", "import error", "parse error", "broken DAG", or asks to "trigger a pipeline", "debug import errors", "check Airflow health", "list connections", "retry a run", or any Airflow operation. Do NOT use for warehouse/SQL analytics on Airflow metadata tables — use analyzing-data instead.
tools
Build Airflow 3.1+ plugins that embed FastAPI apps, custom UI pages, React components, middleware, macros, and operator links directly into the Airflow UI. Use this skill whenever the user wants to create an Airflow plugin, add a custom UI page or nav entry to Airflow, build FastAPI-backed endpoints inside Airflow, serve static assets from a plugin, embed a React app in the Airflow UI, add middleware to the Airflow API server, create custom operator extra links, or call the Airflow REST API from inside a plugin. Also trigger when the user mentions AirflowPlugin, fastapi_apps, external_views, react_apps, plugin registration, or embedding a web app in Airflow 3.1+. If someone is building anything custom inside Airflow 3.1+ that involves Python and a browser-facing interface, this skill almost certainly applies.
data-ai
Use when the user needs human-in-the-loop workflows in Airflow (approval/reject, form input, or human-driven branching). Covers ApprovalOperator, HITLOperator, HITLBranchOperator, HITLEntryOperator, HITLTrigger. Requires Airflow 3.1+. Does not cover AI/LLM calls (see airflow-ai).
development
Detects and fixes common code smells during review or refactoring. Invoke whenever reviewing code for quality issues, before merging a PR, when refactoring legacy code, or when the user asks about code quality, anti-patterns, or technical debt. Detects: over-abstraction, complex inheritance, large functions, tight coupling, hidden dependencies, magic numbers, boolean traps, swallowed exceptions, global state, and duplicate code. Provides specific fixes with before/after examples. Also invoke when someone says "review this code", "is this clean?", "can I improve this?", "this feels messy", or "find problems in my code".