> pytest
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.
curl "https://skillshub.wtf/TerminalSkills/skills/pytest?format=md"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="alice@example.com")
assert user.name == "Alice"
assert user.email == "alice@example.com"
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("user@example.com") is True
assert validate_email("user+tag@example.co.uk") is True
class TestUserService:
"""Group related tests in a class."""
def test_duplicate_email_raises(self):
create_user(name="Alice", email="alice@example.com")
with pytest.raises(ValueError, match="Email already exists"):
create_user(name="Bob", email="alice@example.com")
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="test@example.com", 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.
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.