mcpField
P
Pytest Testing

Pytest Testing

github.com/pluginagentmarketplace测试与质量6528 次安装43 周前更新
代码仓库

关于 Pytest Testing

面向 Python 开发者的 pytest 测试学习技能,涵盖测试设计、测试驱动开发和 CI 集成。

主要功能

  1. 01单元、集成和功能测试
  2. 02Fixture 与测试设置
  3. 03模拟外部依赖
  4. 04测试驱动开发
  5. 05覆盖率与 CI 集成

适用场景

  1. 01为 Python 项目构建 pytest 测试套件
  2. 02使用模拟请求测试 API
  3. 03添加覆盖率报告和 CI 检查

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pluginagentmarketplace/custom-plugin-python --skill pytest-testing

安装后在 Claude Code 中输入/pytest-testing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
config.yaml
references/
GUIDE.md
scripts/
helper.py

详细介绍

Pytest 测试

概述

使用 Python 最受欢迎的测试框架 pytest,掌握软件测试。学习测试驱动开发(TDD)、编写易于维护的测试,并通过全面的测试策略确保代码质量。

学习目标

  • 使用 pytest 编写单元、集成和功能测试
  • 使用 fixture 进行测试准备和清理
  • 有效模拟外部依赖
  • 实施测试驱动开发(TDD)
  • 衡量并提高代码覆盖率
  • 将测试集成到 CI/CD 流水线中

核心主题

1. Pytest 基础
  • 测试发现和命名约定
  • 断言和比较
  • 测试组织(文件、类、模块)
  • 运行测试(命令行选项)
  • 标记和测试选择
  • 参数化测试

代码示例:

# test_calculator.py
import pytest

def add(a, b):
    return a + b

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

# Basic test
def test_add():
    assert add(2, 3) == 5
    assert add(-1, 1) == 0
    assert add(0, 0) == 0

# Test exceptions
def test_divide_by_zero():
    with pytest.raises(ValueError, match="Cannot divide by zero"):
        divide(10, 0)

# Parametrized test
@pytest.mark.parametrize("a,b,expected", [
    (10, 2, 5),
    (20, 4, 5),
    (100, 10, 10),
    (-10, 2, -5),
])
def test_divide(a, b, expected):
    assert divide(a, b) == expected

# Test with marker
@pytest.mark.slow
def test_complex_operation():
    # This test takes a long time
    result = sum(range(1000000))
    assert result == 499999500000
2. Fixture 与测试准备
  • Fixture 作用域(函数、类、模块、会话)
  • Fixture 依赖
  • 参数化 Fixture
  • 内置 Fixture(tmpdir、capsys、monkeypatch)
  • 用于共享 Fixture 的 conftest.py

代码示例:

# conftest.py
import pytest
import tempfile
from pathlib import Path

@pytest.fixture
def sample_data():
    """Provide sample data for tests"""
    return {
        'users': [
            {'id': 1, 'name': 'Alice', 'email': '[email protected]'},
            {'id': 2, 'name': 'Bob', 'email': '[email protected]'},
        ]
    }

@pytest.fixture
def temp_file():
    """Create temporary file for testing"""
    with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
        f.write("Test data")
        temp_path = f.name
    yield temp_path
    # Cleanup
    Path(temp_path).unlink()

@pytest.fixture(scope='module')
def database_connection():
    """Module-scoped database connection"""
    db = DatabaseConnection('test.db')
    db.connect()
    yield db
    db.close()

# test_users.py
def test_user_count(sample_data):
    assert len(sample_data['users']) == 2

def test_user_names(sample_data):
    names = [user['name'] for user in sample_data['users']]
    assert 'Alice' in names
    assert 'Bob' in names

def test_file_operations(temp_file):
    content = Path(temp_file).read_text()
    assert content == "Test data"
3. 模拟与测试替身
  • unittest.mock 基础
  • 模拟函数和方法
  • 修补对象
  • Mock 断言
  • 副作用和返回值
  • 使用外部依赖进行测试

代码示例:

# api_client.py
import requests

class APIClient:
    def __init__(self, base_url):
        self.base_url = base_url

    def get_user(self, user_id):
        response = requests.get(f"{self.base_url}/users/{user_id}")
        response.raise_for_status()
        return response.json()

    def create_user(self, user_data):
        response = requests.post(f"{self.base_url}/users", json=user_data)
        response.raise_for_status()
        return response.json()

# test_api_client.py
from unittest.mock import Mock, patch
import pytest

@patch('api_client.requests.get')
def test_get_user(mock_get):
    # Setup mock
    mock_response = Mock()
    mock_response.json.return_value = {'id': 1, 'name': 'Alice'}
    mock_response.raise_for_status.return_value = None
    mock_get.return_value = mock_response

    # Test
    client = APIClient('https://api.example.com')
    user = client.get_user(1)

    # Assertions
    assert user['name'] == 'Alice'
    mock_get.assert_called_once_with('https://api.example.com/users/1')

@patch('api_client.requests.post')
def test_create_user(mock_post):
    # Setup mock
    mock_response = Mock()
    mock_response.json.return_value = {'id': 3, 'name': 'Charlie'}
    mock_post.return_value = mock_response

    # Test
    client = APIClient('https://api.example.com')
    user_data = {'name': 'Charlie', 'email': '[email protected]'}
    result = client.create_user(user_data)

    # Assertions
    assert result['id'] == 3
    mock_post.assert_called_once_with(
        'https://api.example.com/users',
        json=user_data
    )
4. 覆盖率与 CI/CD 集成
  • 使用 pytest-cov 衡量代码覆盖率
  • 覆盖率报告(终端、HTML、XML)
  • 设置覆盖率阈值
  • 集成 GitHub Actions
  • 集成 GitLab CI
  • pre-commit 钩子

代码示例:

# pytest.ini
[tool:pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
    --cov=myapp
    --cov-report=html
    --cov-report=term-missing
    --cov-fail-under=80
    -v

# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: |
          pip install -r requirements.txt
          pip install pytest pytest-cov
      - name: Run tests
        run: |
          pytest --cov=myapp --cov-report=xml
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml

# Command line usage
# Run all tests
pytest

# Run with coverage
pytest --cov=myapp

# Generate HTML coverage report
pytest --cov=myapp --cov-report=html

# Run specific test file
pytest tests/test_api.py

# Run tests with marker
pytest -m slow

# Run tests with verbose output
pytest -v

# Stop on first failure
pytest -x

动手实践

项目 1:计算器 TDD

使用测试驱动开发构建计算器。

要求:

  • 在实现之前编写测试
  • 基本运算(加、减、乘、除)
  • 错误处理(除以零)
  • 科学运算(幂、平方根、对数)
  • 测试覆盖率 > 90%

关键技能: TDD 工作流、参数化测试、异常测试

项目 2:API 测试套件

为 REST API 创建全面的测试套件。

要求:

  • 模拟 HTTP 请求
  • 测试 CRUD 操作
  • 错误处理测试
  • 身份验证测试
  • 集成测试
  • 设置 CI/CD 流水线

关键技能: 模拟、Fixture、集成测试

项目 3:数据库测试

使用 Fixture 和事务测试数据库操作。

要求:

  • 设置测试数据库 Fixture
  • 测试 CRUD 操作
  • 事务回滚
  • 数据验证
  • 性能测试
  • 覆盖率报告

关键技能: 数据库 Fixture、清理、性能测试

评估标准

  • 编写清晰、易于维护的测试
  • 合理使用 Fixture
  • 有效模拟外部依赖
  • 实现 >80% 的代码覆盖率
  • 遵循 TDD 原则
  • 将测试集成到 CI/CD 中
  • 编写有意义的断言

资源

官方文档
学习平台
工具

后续步骤

掌握 pytest 后,继续探索:

  • 基于属性的测试 - Hypothesis 库
  • 性能测试 - pytest-benchmark
  • 变异测试 - mutmut
  • 负载测试 - Locust、pytest-load

评论

支持 Markdown