pytest高级

Mattakushi4322026-10-26查看 953复制 739

何时激活:pytest 插件、conftest、自定义标记、测试架构、夹具设计、pytest-xdist、覆盖策略

Download (.md)

📘如何使用这个技能

  1. 1
    复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
  2. 2
    打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
  3. 3
    粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
  4. 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
```
来源:skillsdirectory

评论0

登录后参与评论

还没有评论,来抢沙发吧