Standard Python testing framework for unit tests, fixtures, mocking, and coverage analysis.
Install
mkdir -p .claude/skills/pytest-terminalskills && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16268" && unzip -o skill.zip -d .claude/skills/pytest-terminalskills && rm skill.zipInstalls to .claude/skills/pytest-terminalskills
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Test Python code with pytest. Use when a user asks to write unit tests, set up test fixtures, mock dependencies, run async tests, measure coverage, or implement test-driven development in Python.Key capabilities
- →Write basic unit test functions using plain assert statements.
- →Set up shared test fixtures for database or API clients.
- →Create data-driven tests using parametrize.
- →Mock external services or dependencies for isolated testing.
- →Run tests with various command-line options.
- →Group related tests within classes.
How it works
This skill uses pytest to discover and execute test functions, applying fixtures for setup/teardown, parametrize for data variations, and mocking for dependency isolation.
Inputs & outputs
When to use pytest
- →Writing unit tests in Python
- →Setting up test fixtures
- →Measuring code coverage
About this skill
pytest
Overview
pytest is the standard Python testing framework. It uses plain assert statements (no self.assertEqual), fixtures for setup/teardown, parametrize for data-driven tests, and plugins for async, coverage, and mocking.
Instructions
Step 1: Basic Tests
# tests/test_users.py — Simple test functions
from app.services.users import create_user, validate_email
def test_create_user_returns_user_object():
user = create_user(name="Alice", email="[email protected]")
assert user.name == "Alice"
assert user.email == "[email protected]"
assert user.id is not None
def test_validate_email_rejects_invalid():
assert validate_email("not-an-email") is False
assert validate_email("") is False
assert validate_email("user@") is False
def test_validate_email_accepts_valid():
assert validate_email("[email protected]") is True
assert validate_email("[email protected]") is True
class TestUserService:
"""Group related tests in a class."""
def test_duplicate_email_raises(self):
create_user(name="Alice", email="[email protected]")
with pytest.raises(ValueError, match="Email already exists"):
create_user(name="Bob", email="[email protected]")
Step 2: Fixtures
# conftest.py — Shared fixtures
import pytest
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from app.models import Base
@pytest.fixture
async def db():
"""Fresh database for each test."""
engine = create_async_engine("sqlite+aiosqlite:///:memory:")
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
session_maker = async_sessionmaker(engine, expire_on_commit=False)
async with session_maker() as session:
yield session
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
@pytest.fixture
def sample_user(db):
"""Pre-created user for tests that need one."""
user = User(name="Test User", email="[email protected]", role="member")
db.add(user)
db.commit()
return user
@pytest.fixture
def api_client(db):
"""FastAPI test client with database override."""
from fastapi.testclient import TestClient
from app.main import app
from app.dependencies import get_db
app.dependency_overrides[get_db] = lambda: db
yield TestClient(app)
app.dependency_overrides.clear()
Step 3: Parametrize
# tests/test_pricing.py — Data-driven tests
import pytest
@pytest.mark.parametrize("plan,users,expected_price", [
("free", 1, 0),
("free", 5, 0),
("starter", 1, 29),
("starter", 10, 29),
("pro", 1, 79),
("pro", 50, 79),
("enterprise", 100, 199),
])
def test_calculate_price(plan, users, expected_price):
assert calculate_price(plan, users) == expected_price
@pytest.mark.parametrize("input_text,expected_slug", [
("Hello World", "hello-world"),
(" Spaces Everywhere ", "spaces-everywhere"),
("Special!@#$Characters", "specialcharacters"),
("Already-a-slug", "already-a-slug"),
("UPPERCASE", "uppercase"),
])
def test_slugify(input_text, expected_slug):
assert slugify(input_text) == expected_slug
Step 4: Mocking
# tests/test_notifications.py — Mock external services
from unittest.mock import AsyncMock, patch
@pytest.mark.asyncio
async def test_send_welcome_email(db, sample_user):
with patch("app.services.email.send_email", new_callable=AsyncMock) as mock_send:
mock_send.return_value = {"id": "msg_123"}
result = await send_welcome_email(sample_user.id)
mock_send.assert_called_once_with(
to=sample_user.email,
subject="Welcome!",
template="welcome",
)
assert result["id"] == "msg_123"
@pytest.mark.asyncio
async def test_payment_webhook_handles_failure(api_client):
with patch("app.services.stripe.verify_signature", return_value=True):
response = api_client.post("/webhooks/stripe", json={
"type": "payment_intent.failed",
"data": {"object": {"id": "pi_123"}},
})
assert response.status_code == 200
Step 5: Run
pytest # run all tests
pytest -x # stop on first failure
pytest -k "test_create" # run tests matching pattern
pytest --cov=app --cov-report=html # coverage report
pytest -n auto # parallel execution (pytest-xdist)
Guidelines
- Use plain
assert— pytest rewrites assertions to show detailed failure info. - Fixtures with
yieldhandle cleanup automatically — no try/finally needed. conftest.pyfixtures are available to all tests in the directory and below.- Use
@pytest.mark.asynciofor async tests (requirespytest-asyncioplugin). - Aim for fast tests: in-memory SQLite for unit tests, real database for integration tests.
When not to use it
- →When testing languages other than Python.
- →When the task is not related to writing, running, or managing Python tests.
- →When the user explicitly requests a different testing framework.
Limitations
- →The skill is specific to Python testing with pytest.
- →It requires `pytest-asyncio` for async tests.
- →Fixtures with `yield` handle cleanup automatically.
How it compares
This workflow use pytest's features like plain asserts and fixtures for Python testing, simplifying test writing and maintenance compared to frameworks requiring `self.assertEqual`.
Compared to similar skills
pytest side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| pytest (this skill) | 0 | 3mo | Review | Intermediate |
| python-testing-patterns | 77 | 2mo | Review | Intermediate |
| backtesting-frameworks | 17 | 2mo | No flags | Advanced |
| temporal-python-testing | 8 | 3mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by TerminalSkills
View all by TerminalSkills →You might also like
python-testing-patterns
wshobson
Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development. Use when writing Python tests, setting up test suites, or implementing testing best practices.
backtesting-frameworks
wshobson
Build robust backtesting systems for trading strategies with proper handling of look-ahead bias, survivorship bias, and transaction costs. Use when developing trading algorithms, validating strategies, or building backtesting infrastructure.
temporal-python-testing
wshobson
Test Temporal workflows with pytest, time-skipping, and mocking strategies. Covers unit testing, integration testing, replay testing, and local development setup. Use when implementing Temporal workflow tests or debugging test failures.
home-assistant-integration-knowledge
home-assistant
Everything you need to know to build, test and review Home Assistant Integrations. If you're looking at an integration, you must use this as your primary reference.
testing-python
jlowin
Write and evaluate effective Python tests using pytest. Use when writing tests, reviewing test code, debugging test failures, or improving test coverage. Covers test design, fixtures, parameterization, mocking, and async testing.
pr-review
pytorch
Review PyTorch pull requests for code quality, test coverage, security, and backward compatibility. Use when reviewing PRs, when asked to review code changes, or when the user mentions "review PR", "code review", or "check this PR".