원클릭으로
pytest
Execute and generate pytest tests for Python projects with fixtures, parametrization, and mocking support
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Execute and generate pytest tests for Python projects with fixtures, parametrization, and mocking support
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Third-party API integration patterns with webhook verification, idempotency, retry with Polly, circuit breakers, and HttpClientFactory. Use when integrating external services like Stripe, Twilio, SendGrid, or HubSpot.
Third-party API integration patterns with webhook verification, idempotency, retry with Polly, circuit breakers, and HttpClientFactory. Use when integrating external services like Stripe, Twilio, SendGrid, or HubSpot.
.NET 9 development with Clean Architecture, MediatR CQRS, Entity Framework Core, minimal APIs, and dependency injection. Use when writing C# code or working with .NET projects.
Azure DevOps YAML pipelines with multi-stage deployments, template references, variable groups, and environment approvals. Use when building CI/CD pipelines in Azure DevOps.
Azure DevOps YAML pipelines with multi-stage deployments, template references, variable groups, and environment approvals. Use when building CI/CD pipelines in Azure DevOps.
Production browser automation with Playwright for RPA, web scraping, and workflow automation. Resilient selectors, session persistence, retry patterns, and Playwright 1.56 agents. Distinct from E2E testing.
| name | pytest |
| description | Execute and generate pytest tests for Python projects with fixtures, parametrization, and mocking support |
| allowed-tools | Read, Write, Edit, Bash, Grep, Glob |
Generate pytest-based test code that uses class-based organization, leverages pytest's native features, and ensures comprehensive coverage.
Out of Scope: unittest.TestCase tests, integration tests requiring
full application context, performance/load testing.
TestSomething classestest_* functionssetUp/tearDown@pytest.mark.parametrize for multiple inputstest_* with clear names__init__: Test classes should not define __init__ methodsproject_root/
├── src/
│ └── mypackage/
│ ├── __init__.py
│ ├── parser.py
│ └── validator.py
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Shared fixtures
│ ├── test_parser.py
│ └── test_validator.py
├── pytest.ini
└── requirements-test.txt
test_*.py or *_test.pyTestSomething (PascalCase with Test prefix)test_* (snake_case with test_ prefix)Always organize tests into classes. Never use top-level test functions.
# BAD: Top-level test function
def test_normalize_token_success():
result = normalize_token(" Hello ")
assert result == "hello"
# GOOD: Class-based organization
class TestNormalizeToken:
"""Tests for the normalize_token function."""
def test_success_with_whitespace(self):
result = normalize_token(" Hello ")
assert result == "hello"
def test_empty_string(self):
result = normalize_token("")
assert result == ""
def test_none_raises_error(self):
with pytest.raises(ValueError, match="cannot be None"):
normalize_token(None)
import pytest
from mypackage.parser import Parser, ParserError
class TestParserInitialization:
"""Tests for Parser initialization."""
def test_default_configuration(self):
parser = Parser()
assert parser.strict_mode is False
assert parser.encoding == "utf-8"
def test_custom_configuration(self):
parser = Parser(strict_mode=True, encoding="latin-1")
assert parser.strict_mode is True
def test_invalid_encoding_raises_error(self):
with pytest.raises(ValueError, match="Invalid encoding"):
Parser(encoding="invalid-encoding")
class TestParserParsing:
"""Tests for Parser parsing functionality."""
def test_parse_valid_input(self):
parser = Parser()
result = parser.parse("valid data")
assert result == {"data": "valid data"}
def test_parse_empty_input(self):
parser = Parser()
result = parser.parse("")
assert result == {}
Use fixtures for setup instead of setUp/tearDown or __init__.
# BAD: Using unittest-style setUp
class TestDatabase:
def setUp(self): # Won't work in pytest!
self.db = Database()
# GOOD: Using pytest fixtures
@pytest.fixture
def db():
"""Provide a Database instance."""
database = Database()
yield database
database.disconnect() # Teardown
class TestDatabase:
"""Tests for Database class."""
def test_connect(self, db):
db.connect()
assert db.is_connected
def test_execute_query(self, db):
db.connect()
result = db.execute("SELECT 1")
assert result == [1]
# Function scope (default): New instance per test
@pytest.fixture
def cache():
"""Fresh cache for each test."""
return Cache()
# Class scope: Shared across tests in a class
@pytest.fixture(scope="class")
def config():
"""Shared immutable configuration."""
return Config.from_file("test_config.yaml")
# Module scope: Shared across module
@pytest.fixture(scope="module")
def expensive_resource():
"""Expensive resource shared across module."""
resource = ExpensiveResource()
resource.initialize()
yield resource
resource.cleanup()
# tests/conftest.py
import pytest
from unittest.mock import Mock
@pytest.fixture
def mock_logger():
"""Provide a mock logger for testing."""
return Mock()
@pytest.fixture
def sample_data():
"""Provide sample test data."""
return {
"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
]
}
@pytest.fixture
def temp_file(tmp_path):
"""Provide a temporary file for testing."""
file_path = tmp_path / "test_file.txt"
file_path.write_text("test content")
return file_path
Use @pytest.mark.parametrize to test multiple inputs.
# BAD: Duplicated test methods
class TestValidateEmail:
def test_valid_email_1(self):
assert validate_email("user@example.com") is True
def test_valid_email_2(self):
assert validate_email("test@example.co.uk") is True
# GOOD: Parametrized test
class TestValidateEmail:
"""Tests for email validation."""
@pytest.mark.parametrize("email", [
"user@example.com",
"test.user@example.co.uk",
"user+tag@example.com",
])
def test_valid_emails(self, email):
assert validate_email(email) is True
@pytest.mark.parametrize("email", [
"invalid",
"@example.com",
"user@",
"",
])
def test_invalid_emails(self, email):
assert validate_email(email) is False
class TestCalculator:
"""Tests for Calculator class."""
@pytest.mark.parametrize("a,b,expected", [
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
(0.1, 0.2, 0.3),
])
def test_add(self, a, b, expected):
calc = Calculator()
result = calc.add(a, b)
assert result == pytest.approx(expected)
@pytest.mark.parametrize("a,b", [
(1, 0),
(100, 0),
(-5, 0),
])
def test_divide_by_zero_raises_error(self, a, b):
calc = Calculator()
with pytest.raises(ValueError, match="Cannot divide by zero"):
calc.divide(a, b)
class TestParseConfig:
"""Tests for configuration parsing."""
@pytest.mark.parametrize("config_string,expected", [
pytest.param(
"key=value",
{"key": "value"},
id="simple_key_value"
),
pytest.param(
"key1=value1\nkey2=value2",
{"key1": "value1", "key2": "value2"},
id="multiple_entries"
),
pytest.param(
"",
{},
id="empty_config"
),
])
def test_parse_config(self, config_string, expected):
result = parse_config(config_string)
assert result == expected
import pytest
from unittest.mock import Mock, patch
from mypackage.api_client import ApiClient, ApiError
class TestApiClient:
"""Tests for ApiClient class."""
@pytest.fixture
def mock_response(self):
"""Provide a mock HTTP response."""
response = Mock()
response.status_code = 200
response.json.return_value = {"data": "success"}
return response
def test_fetch_data_success(self, mock_response):
with patch("requests.get", return_value=mock_response):
client = ApiClient(base_url="https://api.example.com")
result = client.fetch_data("/endpoint")
assert result == {"data": "success"}
def test_fetch_data_http_error(self):
with patch("requests.get") as mock_get:
mock_get.side_effect = Exception("Connection error")
client = ApiClient(base_url="https://api.example.com")
with pytest.raises(ApiError, match="Failed to fetch"):
client.fetch_data("/endpoint")
class TestLoadConfig:
"""Tests for configuration loading."""
def test_load_from_environment(self, monkeypatch):
monkeypatch.setenv("API_KEY", "test-key-123")
monkeypatch.setenv("DEBUG", "true")
config = load_config()
assert config.api_key == "test-key-123"
assert config.debug is True
def test_missing_required_env_var(self, monkeypatch):
monkeypatch.delenv("API_KEY", raising=False)
with pytest.raises(ValueError, match="API_KEY is required"):
load_config()
from unittest.mock import patch
from datetime import datetime
class TestScheduler:
"""Tests for Scheduler class."""
def test_is_time_to_run(self):
with patch("mypackage.scheduler.datetime") as mock_dt:
mock_dt.now.return_value = datetime(2025, 1, 1, 10, 0)
scheduler = Scheduler(run_hour=10)
assert scheduler.is_time_to_run() is True
class TestValidateAge:
"""Tests for age validation."""
@pytest.mark.parametrize("age", [0, 18, 100, 120])
def test_valid_ages(self, age):
validate_age(age) # Should not raise
@pytest.mark.parametrize("age,error_message", [
(-1, "Age cannot be negative"),
(151, "Age exceeds maximum"),
])
def test_invalid_ages(self, age, error_message):
with pytest.raises(ValidationError, match=error_message):
validate_age(age)
def test_non_integer_type(self):
with pytest.raises(TypeError, match="must be an integer"):
validate_age("25")
class TestParserErrors:
"""Tests for Parser error handling."""
def test_parse_error_includes_line_number(self):
parser = Parser()
invalid_input = "line1\nline2\ninvalid line 3"
with pytest.raises(ParseError) as exc_info:
parser.parse(invalid_input)
error_message = str(exc_info.value)
assert "line 3" in error_message
assert "invalid" in error_message
Use pytest's tmp_path fixture.
class TestFileManager:
"""Tests for FileManager class."""
def test_write_and_read_file(self, tmp_path):
file_path = tmp_path / "test.txt"
manager = FileManager()
manager.write(file_path, "test content")
content = manager.read(file_path)
assert content == "test content"
def test_read_nonexistent_file_raises_error(self, tmp_path):
file_path = tmp_path / "nonexistent.txt"
manager = FileManager()
with pytest.raises(FileNotFoundError):
manager.read(file_path)
from unittest.mock import Mock, call
class TestDataProcessor:
"""Tests for DataProcessor class."""
def test_process_logs_progress(self):
mock_logger = Mock()
processor = DataProcessor(logger=mock_logger)
processor.process([{"id": 1}, {"id": 2}])
mock_logger.info.assert_has_calls([
call("Processing started"),
call("Processed 2 items"),
call("Processing completed"),
])
def test_process_calls_callbacks(self):
callback = Mock()
processor = DataProcessor(on_complete=callback)
processor.process([{"id": 1}])
callback.assert_called_once_with(success=True, count=1)
# BAD
def test_add():
assert add(1, 2) == 3
# GOOD
class TestMathOperations:
def test_add(self):
assert add(1, 2) == 3
# BAD
import unittest
class TestParser(unittest.TestCase):
def setUp(self):
self.parser = Parser()
# GOOD
import pytest
@pytest.fixture
def parser():
return Parser()
class TestParser:
def test_parse(self, parser):
result = parser.parse("data")
assert result == expected
# BAD: Tests depend on each other
class TestBadSequence:
shared_state = None
def test_step_1(self):
self.shared_state = create_resource()
def test_step_2(self):
self.shared_state.process() # Depends on step_1!
# GOOD: Tests are independent
@pytest.fixture
def resource():
return create_resource()
class TestGoodIsolation:
def test_create_resource(self, resource):
assert resource is not None
def test_process_resource(self, resource):
result = resource.process()
assert result is not None
TestSomething classes@pytest.mark.parametrize for multiple similar test casespytest.raises() to test exceptionstmp_path fixture for file testingmonkeypatch for environment variablespytest.approx() for floating-point comparisonstest_* functionsunittest.TestCasesetUp/tearDown methods__init__ in test classestime.sleep() in teststmp_path)Test* classestest_* functionsunittest.TestCase inheritancesetUp/tearDown@pytest.mark.parametrizepytest.raises()time.sleep() calls in teststmp_path fixture[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
--strict-markers
--verbose
--tb=short
--cov=src
--cov-report=term-missing
markers =
slow: marks tests as slow
integration: marks tests as integration tests
unit: marks tests as unit tests
Good tests are isolated, readable, and focused on behavior. They document what the code should do and catch regressions early.