pytest高级
Mattakushi4322026-10-26查看 953复制 739
何时激活:pytest 插件、conftest、自定义标记、测试架构、夹具设计、pytest-xdist、覆盖策略
📘如何使用这个技能
- 1复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
- 2打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
- 3粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
- 4直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景
💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。
SKILL.md3408 chars
---
name: pytest-advanced
description: "When to activate: pytest plugins, conftest, custom markers, test architecture, fixtures design, pytest-xdist, coverage strategies"
origin: zakr
metadata:
namespace: zakr/devtools-pack
version: 1.0.0
category: engineering
language: python
platforms: [claude-code, codex, gemini-cli, cursor, aider, windsurf]
---
# Advanced pytest Patterns
## Conftest Architecture
```
tests/
├── conftest.py # session-scoped fixtures (db, engine, settings override)
├── unit/
│ ├── conftest.py # unit-test-specific fixtures (no db)
│ └── test_validators.py
├── integration/
│ ├── conftest.py # integration fixtures (real db, real redis)
│ └── test_user_flow.py
└── e2e/
├── conftest.py # httpx.AsyncClient, live app
└── test_signup.py
```
## Custom Markers
```python
# conftest.py
import pytest
def pytest_configure(config):
config.addinivalue_line("markers", "slow: marks tests as slow (deselect with -m 'not slow')")
config.addinivalue_line("markers", "integration: marks integration tests requiring db/redis")
config.addinivalue_line("markers", "external: marks tests that call real external APIs")
# Usage
@pytest.mark.slow
@pytest.mark.integration
async def test_report_generation(db, client):
...
```
## Fixture Factories with faker
```python
from faker import Faker
import pytest
fake = Faker()
@pytest.fixture
async def make_user(db):
created = []
async def _make(**kwargs) -> User:
data = {
"email": fake.email(),
"name": fake.name(),
"password": "test_password_123",
**kwargs,
}
user = await user_service.create(db, data)
created.append(user)
return user
yield _make
# cleanup
for user in created:
await db.delete(user)
await db.commit()
```
## Parametrize with Fixtures (pytest-lazy-fixture / indirect)
```python
@pytest.mark.parametrize("role,expected_status", [
("admin", 200),
("viewer", 403),
("anonymous", 401),
])
async def test_admin_endpoint_access(role, expected_status, client, make_user):
if role != "anonymous":
user = await make_user(role=role)
client.force_authenticate(user=user)
response = await client.get("/api/admin/users")
assert response.status_code == expected_status
```
## Parallel Test Execution
```bash
# Install pytest-xdist
pip install pytest-xdist
# Run in parallel
pytest -n auto # auto-detect CPU count
pytest -n 4 # 4 workers
pytest -n auto --dist=loadscope # group by module (good for db tests)
```
## Coverage Configuration
```toml
[tool.pytest.ini_options]
addopts = ["--cov=app", "--cov-report=term-missing", "--cov-fail-under=80"]
[tool.coverage.run]
branch = true # measure branch coverage, not just line coverage
omit = ["tests/*", "*/migrations/*", "app/main.py"]
[tool.coverage.report]
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"raise NotImplementedError",
"@(abc\\.)?abstractmethod",
]
```
## Snapshot Testing
```python
import pytest
def test_api_response_shape(snapshot, client):
response = client.get("/api/v1/users/1")
assert response.json() == snapshot # generates snapshot on first run, compares on subsequent
# Uses pytest-snapshot or syrupy
```