/pytest-patterns
Python testing skill using pytest, covering fixtures, parametrize, markers, conftest, plugins, mocking, and advanced testing patterns.
$ npx -y skills add PramodDutta/qaskills --skill pytest-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/pytest-patterns
Context preview
The summary Claude sees to decide when to auto-load this skill.
Python testing skill using pytest, covering fixtures, parametrize, markers, conftest, plugins, mocking, and advanced testing patterns.
SKILL.md
pytest-patterns.SKILL.mdname: pytest-patterns
description: Python testing skill using pytest, covering fixtures, parametrize, markers, conftest, plugins, mocking, and advanced testing patterns.
license: MIT
metadata:
author: thetestingacademy
version: 1.0.0
source: https://qaskills.sh/skills/thetestingacademy/pytest-patterns
Pytest Patterns Skill
You are an expert Python developer specializing in testing with pytest. When the user asks you to write, review, or debug pytest tests, follow these detailed instructions.
Core Principles
1. **Convention over configuration** -- pytest discovers tests automatically by naming conventions. 2. **Fixtures for setup** -- Use fixtures instead of setUp/tearDown methods. 3. **Parametrize for coverage** -- Use `@pytest.mark.parametrize` for data-driven tests. 4. **Descriptive test names** -- Function names should describe the expected behavior. 5. **Minimal test scope** -- Each test verifies one behavior.
Project Structure
project/
src/
myapp/
__init__.py
services/
user_service.py
order_service.py
models/
user.py
utils/
validators.py
tests/
__init__.py
conftest.py
unit/
__init__.py
test_user_service.py
test_validators.py
integration/
__init__.py
conftest.py
test_user_api.py
fixtures/
user_fixtures.py
pyproject.toml
pytest.iniConfiguration
# pytest.ini
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = -v --tb=short --strict-markers
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: marks integration tests
smoke: marks smoke tests
unit: marks unit tests# pyproject.toml
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v --tb=short --strict-markers --cov=src --cov-report=term-missing"
markers = [
"slow: marks tests as slow",
"integration: marks integration tests",
"smoke: marks smoke tests",
]
[tool.coverage.run]
source = ["src"]
omit = ["tests/*", "*/__init__.py"]
[tool.coverage.report]
fail_under = 80
show_missing = trueFixtures
Basic Fixtures
# conftest.py
import pytest
from myapp.services.user_service import UserService
from myapp.models.user import User
@pytest.fixture
def sample_user():
"""Create a sample user for testing."""
return User(
id="user-123",
email="test@example.com",
name="Test User",
role="user",
)
@pytest.fixture
def admin_user():
"""Create an admin user for testing."""
return User(
id="admin-123",
email="admin@example.com",
name="Admin User",
role="admin",
)
@pytest.fixture
def user_service(mock_user_repo, mock_email_service):
"""Create UserService with mocked dependencies."""
return UserService(
user_repo=mock_user_repo,
email_service=mock_email_service,
)Fixture Scopes
@pytest.fixture(scope="session")
def database_connection():
"""Create a database connection once for the entire test session."""
conn = create_connection("test_db")
yield conn
conn.close()
@pytest.fixture(scope="module")
def test_data(database_connection):
"""Seed test data once per module."""
seed_test_data(database_connection)
yield
cleanup_test_data(database_connection)
@pytest.fixture(scope="function") # default scope
def fresh_user():
"""Create a fresh user for each test function."""
return create_user(email=f"test-{uuid4()}@example.com")
@pytest.fixture(scope="class")
def shared_resource():
"""Share a resource across all methods in a test class."""
resource = create_expensive_resource()
yield resource
resource.cleanup()Fixture Factories
@pytest.fixture
def make_user():
"""Factory fixture that creates users with custom attributes."""
created_users = []
def _make_user(
email: str = None,
name: str = "Test User",
role: str = "user",
) -> User:
user = User(
id=str(uuid4()),
email=email or f"test-{uuid4()}@example.com",
name=name,
role=role,
)
created_users.append(user)
return user
yield _make_user
# Cleanup
for user in created_users:
try:
delete_user(user.id)
except Exception:
pass
# Usage in tests
def test_admin_permissions(make_user):
admin = make_user(role="admin")
viewer = make_user(role="viewer")
assert admin.can_delete_users()
assert not viewer.can_delete_users()Yield Fixtures (Setup/Teardown)
@pytest.fixture
def temp_file(tmp_path):
"""Create a temporary file and clean up after test."""
file_path = tmp_path / "test_data.json"
file_path.write_text('{"key": "value"}')
yield file_path
# Teardown happens automatically (tmp_path handles cleanup)
@pytest.fixture
def mock_server():
"""Start a mock HTTP server for testing."""
server = MockServer(port=8089)
server.start()
yield server
server.stop()
@pytest.fixture
def db_transaction(database_connection):
"""Wrap each test in a database transaction that rolls back."""
transaction = database_connection.begin()
yield database_connection
transaction.rollback()Parametrize
Basic Parametrize
@pytest.mark.parametrize("email,expected", [
("user@example.com", True),
("first.last@domain.co.uk", True),
("user+tag@example.com", True),
("", False),
("not-an-email", False),
("@missing-local.com", False),
("missing-at.com", False),
])
def test_is_valid_email(email, expected):
assert is_valid_email(email) == expectedMultiple Parameters
@pytest.mark.parametrize("a,b,expected", [
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
(100, 200, 300),
])
defRead more
name: pytest-patterns description: Python testing skill using pytest, covering fixtures, parametrize, markers, conftest, plugins, mocking, and advanced testing patterns. license: MIT metadata: author: thetestingacademy version: 1.0.0 source: https://qaskills.sh/skills/thetestingacademy/pytest-patterns
Pytest Patterns Skill
You are an expert Python developer specializing in testing with pytest. When the user asks you to write, review, or debug pytest tests, follow these detailed instructions.
Core Principles
1. **Convention over configuration** -- pytest discovers tests automatically by naming conventions. 2. **Fixtures for setup** -- Use fixtures instead of setUp/tearDown methods. 3. **Parametrize for coverage** -- Use `@pytest.mark.parametrize` for data-driven tests. 4. **Descriptive test names** -- Function names should describe the expected behavior. 5. **Minimal test scope** -- Each test verifies one behavior.
Project Structure
project/
src/
myapp/
__init__.py
services/
user_service.py
order_service.py
models/
user.py
utils/
validators.py
tests/
__init__.py
conftest.py
unit/
__init__.py
test_user_service.py
test_validators.py
integration/
__init__.py
conftest.py
test_user_api.py
fixtures/
user_fixtures.py
pyproject.toml
pytest.iniConfiguration
# pytest.ini
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = -v --tb=short --strict-markers
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: marks integration tests
smoke: marks smoke tests
unit: marks unit tests# pyproject.toml
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v --tb=short --strict-markers --cov=src --cov-report=term-missing"
markers = [
"slow: marks tests as slow",
"integration: marks integration tests",
"smoke: marks smoke tests",
]
[tool.coverage.run]
source = ["src"]
omit = ["tests/*", "*/__init__.py"]
[tool.coverage.report]
fail_under = 80
show_missing = trueFixtures
Basic Fixtures
# conftest.py
import pytest
from myapp.services.user_service import UserService
from myapp.models.user import User
@pytest.fixture
def sample_user():
"""Create a sample user for testing."""
return User(
id="user-123",
email="test@example.com",
name="Test User",
role="user",
)
@pytest.fixture
def admin_user():
"""Create an admin user for testing."""
return User(
id="admin-123",
email="admin@example.com",
name="Admin User",
role="admin",
)
@pytest.fixture
def user_service(mock_user_repo, mock_email_service):
"""Create UserService with mocked dependencies."""
return UserService(
user_repo=mock_user_repo,
email_service=mock_email_service,
)Fixture Scopes
@pytest.fixture(scope="session")
def database_connection():
"""Create a database connection once for the entire test session."""
conn = create_connection("test_db")
yield conn
conn.close()
@pytest.fixture(scope="module")
def test_data(database_connection):
"""Seed test data once per module."""
seed_test_data(database_connection)
yield
cleanup_test_data(database_connection)
@pytest.fixture(scope="function") # default scope
def fresh_user():
"""Create a fresh user for each test function."""
return create_user(email=f"test-{uuid4()}@example.com")
@pytest.fixture(scope="class")
def shared_resource():
"""Share a resource across all methods in a test class."""
resource = create_expensive_resource()
yield resource
resource.cleanup()Fixture Factories
@pytest.fixture
def make_user():
"""Factory fixture that creates users with custom attributes."""
created_users = []
def _make_user(
email: str = None,
name: str = "Test User",
role: str = "user",
) -> User:
user = User(
id=str(uuid4()),
email=email or f"test-{uuid4()}@example.com",
name=name,
role=role,
)
created_users.append(user)
return user
yield _make_user
# Cleanup
for user in created_users:
try:
delete_user(user.id)
except Exception:
pass
# Usage in tests
def test_admin_permissions(make_user):
admin = make_user(role="admin")
viewer = make_user(role="viewer")
assert admin.can_delete_users()
assert not viewer.can_delete_users()Yield Fixtures (Setup/Teardown)
@pytest.fixture
def temp_file(tmp_path):
"""Create a temporary file and clean up after test."""
file_path = tmp_path / "test_data.json"
file_path.write_text('{"key": "value"}')
yield file_path
# Teardown happens automatically (tmp_path handles cleanup)
@pytest.fixture
def mock_server():
"""Start a mock HTTP server for testing."""
server = MockServer(port=8089)
server.start()
yield server
server.stop()
@pytest.fixture
def db_transaction(database_connection):
"""Wrap each test in a database transaction that rolls back."""
transaction = database_connection.begin()
yield database_connection
transaction.rollback()Parametrize
Basic Parametrize
@pytest.mark.parametrize("email,expected", [
("user@example.com", True),
("first.last@domain.co.uk", True),
("user+tag@example.com", True),
("", False),
("not-an-email", False),
("@missing-local.com", False),
("missing-at.com", False),
])
def test_is_valid_email(email, expected):
assert is_valid_email(email) == expectedMultiple Parameters
@pytest.mark.parametrize("a,b,expected", [
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
(100, 200, 300),
])
defQA Skills Directory QA Skills is a curated directory of testing-specific skills for AI coding agents (Claude Code, Cursor, Copilot, etc.).
Repo: PramodDutta/qaskills
Other skills on qaskills.
- /add-seed-skills
Use when adding or editing QA skills in seed-skills/ or getting them onto the live qaskills.sh catalog, e.g. "add N new skills", "create a seed skill for X", "seed the database", "the skill page is empty", "skill 404s on the site".
Open skill - /publish-seo-batch
Use when publishing SEO blog articles to qaskills.sh, e.g. "publish today's articles", "daily SEO batch", "write 10 articles from keyword research", "add a blog post", or any request that creates files under packages/web/src/app/blog/posts.
Open skill - /ship-prod
Use when deploying qaskills.sh to production, verifying whether a deploy landed, or when a push to main did not show up on the live site, e.g. "deploy", "ship it", "push this live", "is prod updated?", "the site still shows the old version".
Open skill - /api-testing-rest
Comprehensive RESTful API testing patterns covering HTTP methods, status codes, request/response validation, authentication, error handling, and contract testing.
Open skill - /claude-code-qa
The complete QA skill for Claude Code — turn Claude into an expert QA engineer that picks the right test type, writes reliable Playwright, Cypress, and pytest tests, eliminates flaky tests, enforces coverage, and wires up CI. Claude Code QA testing done right.
Open skill - /cypress-e2e
End-to-end testing skill using Cypress for web applications, covering custom commands, network intercepts, fixtures, cy.session, and component testing patterns.
Open skill

