好的!下面给你详细介绍 Python 测试框架 pytest,以及如何执行测试用例。


Python 单元测试框架之 pytest — 如何执行测试用例


一、pytest 简介

  • pytest 是 Python 中非常流行的测试框架,支持简单的测试用例编写,功能强大且扩展性好。
  • 支持断言重写、fixture 机制、参数化测试等。

二、安装 pytest

pip install pytest

三、编写测试用例示例

在项目目录中创建测试文件,文件名推荐以 test_ 开头,函数名也以 test_ 开头。

# test_sample.py

def func(x):
    return x + 1

def test_func():
    assert func(3) == 4

def test_func_fail():
    assert func(3) == 5

四、执行测试用例

1. 在命令行直接执行

进入测试文件所在目录,运行:

pytest
  • 会自动搜寻当前目录及子目录下所有 test_*.py 或 *_test.py 文件,执行其中的测试函数。
  • 默认输出详细的测试结果。

2. 指定某个测试文件执行

pytest test_sample.py

3. 指定某个测试函数执行

pytest test_sample.py::test_func

五、常用命令参数

参数说明
-v显示详细测试过程
-q简洁输出
-k "表达式"只执行匹配表达式的测试用例
--maxfail=N失败达到 N 个时停止测试
--tb=short/line/no调试信息显示简短、单行或不显示
-m "标记名"运行带有指定标记的测试(需使用 @pytest.mark

六、示例:详细执行

pytest -v test_sample.py

输出类似:

test_sample.py::test_func PASSED
test_sample.py::test_func_fail FAILED

七、集成其他功能

  • 参数化测试
import pytest

@pytest.mark.parametrize("input,expected", [(1,2), (3,4), (5,6)])
def test_param(input, expected):
    assert input + 1 == expected
  • 使用 Fixture
import pytest

@pytest.fixture
def resource():
    print("Setup resource")
    yield "resource"
    print("Teardown resource")

def test_with_resource(resource):
    assert resource == "resource"

好的!下面给你详细介绍 pytest 的高级用法,包括自定义插件、钩子函数,以及如何进行异常测试和跳过测试,最后也会简单说明如何和持续集成(CI)结合。


pytest 高级用法详解


一、自定义插件和钩子函数

1. 钩子函数 (Hook Functions)

pytest 支持钩子机制,可以在测试运行的不同阶段插入自定义逻辑。

例如,打印测试开始和结束提示:

# conftest.py(项目根目录或测试目录)

def pytest_runtest_setup(item):
    print(f"\n开始执行测试: {item.name}")

def pytest_runtest_teardown(item, nextitem):
    print(f"测试结束: {item.name}")

常用钩子函数:

  • pytest_sessionstart(session):测试会话开始
  • pytest_sessionfinish(session, exitstatus):测试会话结束
  • pytest_runtest_setup(item):单个测试用例执行前
  • pytest_runtest_teardown(item, nextitem):单个测试用例执行后

2. 自定义命令行参数

可以通过插件或 conftest.py 自定义命令行参数:

# conftest.py

def pytest_addoption(parser):
    parser.addoption(
        "--env", action="store", default="dev", help="测试环境选择"
    )

@pytest.fixture
def env(request):
    return request.config.getoption("--env")

测试用例中:

def test_env(env):
    print(f"当前测试环境: {env}")

运行:

pytest --env=prod

二、异常测试(验证是否抛出预期异常)

pytest 通过 pytest.raises() 上下文管理器验证异常:

import pytest

def func(x):
    if x == 0:
        raise ValueError("x 不能为0")
    return 10 / x

def test_func_exception():
    with pytest.raises(ValueError) as excinfo:
        func(0)
    assert "不能为0" in str(excinfo.value)

三、跳过测试和条件跳过

1. 跳过测试

使用装饰器:

import pytest

@pytest.mark.skip(reason="该功能尚未实现")
def test_not_implemented():
    pass

2. 条件跳过

import sys

@pytest.mark.skipif(sys.platform == "win32", reason="Windows 不支持")
def test_not_on_windows():
    pass

四、参数化组合与间接参数化

参数化可以组合多组数据,间接参数化可用 fixture 处理复杂数据:

import pytest

@pytest.mark.parametrize("x,y", [(1,2), (3,4)])
@pytest.mark.parametrize("z", [10, 20])
def test_multi(x, y, z):
    assert (x + y) * z > 0

五、pytest 与持续集成(CI)集成简述

  • 常见 CI 工具:Jenkins、GitHub Actions、GitLab CI、Travis CI 等。
  • 只需在 CI 脚本里运行:
pytest --junitxml=report.xml
  • 生成的 report.xml 可被 CI 工具识别,显示测试报告。
  • 可结合覆盖率工具 coverage.py
pytest --cov=your_package --cov-report=xml
  • 报告数据用于质量分析和门禁控制。

好的!下面给你一个完整示例,演示如何开发一个简单的 pytest 插件,以及如何在 GitHub Actions 中集成 pytest 和 coverage 来实现自动测试和覆盖率报告。


一、简单 pytest 插件开发示例


1. 插件功能

示例插件功能:在每个测试用例开始和结束时打印日志。


2. 目录结构

my_pytest_plugin/
├── conftest.py
├── test_sample.py
├── setup.py
├── README.md

3. 插件代码示例

conftest.py

def pytest_runtest_setup(item):
    print(f"\n[PLUGIN] 开始测试: {item.name}")

def pytest_runtest_teardown(item, nextitem):
    print(f"[PLUGIN] 测试结束: {item.name}")

test_sample.py

def test_example():
    assert 1 + 1 == 2

setup.py

from setuptools import setup

setup(
    name='my_pytest_plugin',
    version='0.1',
    py_modules=['conftest'],
    entry_points={
        'pytest11': [
            'myplugin = conftest',
        ],
    },
)

4. 使用插件

  • 本地测试:
pytest -v
  • 输出会包含插件打印的开始和结束信息。

二、GitHub Actions 集成 pytest + coverage 示例


1. 在项目根目录创建 .github/workflows/python-test.yml

name: Python Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        python-version: [3.8, 3.9, 3.10]

    steps:
    - uses: actions/checkout@v3

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pytest coverage

    - name: Run tests with coverage
      run: |
        coverage run -m pytest
        coverage xml

    - name: Upload coverage report
      uses: actions/upload-artifact@v3
      with:
        name: coverage-report
        path: coverage.xml

2. 说明

  • coverage run -m pytest 运行测试并收集覆盖率。
  • 生成 coverage.xml,上传为构建产物。
  • 可结合 Codecov、Coveralls 等服务进一步分析。

三、总结

功能说明
pytest 插件开发用钩子函数扩展测试运行逻辑
GitHub Actions 集成自动测试 + 覆盖率报告生成
持续集成可自动触发每次推送/PR 自动执行测试