人人都会AI编程

24.1 pytest 测试框架:用例编写、固件、参数化、断言

更新时间:2026-07-12

pytest 是 Python 生态中最主流的测试框架。它比 unittest 更简洁、更强大,大量项目(包括 Django、Flask 本身)都用它来写测试。核心体验可以概括为:用极少量的代码写出易读、好维护的测试

用例编写

  • 自动发现:pytest 会自动查找以 test_ 开头的文件和函数,以及以 Test 开头的类中的 test_ 方法。你只要按规范命名,无需注册。
  • 测试函数即用例:最简单的测试就是一个普通函数,用 assert 断言预期结果。
  # test_calc.py
  def add(a, b):
      return a + b

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

运行 pytest 命令,它自动发现并执行,输出清晰的成功/失败信息。

  • 可读性好:测试逻辑就是普通的 Python 代码,没有多余的样板。团队成员看测试就能知道被测代码的预期行为。

断言

pytest 抛弃了 unittest 中 self.assertEqual() 这类繁琐的断言方法,直接使用 Python 内置的 assert 语句。

  • 优势:当断言失败时,pytest 会智能地展示表达式的值和差异,帮助快速定位问题。例如:
  def test_dict():
      result = {"a": 1, "b": 2}
      assert result == {"a": 1, "b": 3}
  

会给出清晰的对比,告诉你哪个键值不一致。

  • 异常断言:用 pytest.raises 上下文管理器来验证代码是否按预期抛出异常:
  import pytest

  def test_division_by_zero():
      with pytest.raises(ZeroDivisionError):
          1 / 0
  
  • 警告断言:也可用 pytest.warns 验证警告信息的产生。

固件(Fixtures)

固件是 pytest 中管理测试前置资源(如数据库连接、临时文件、测试数据)的核心机制。

  • 定义与注入:用 @pytest.fixture 定义一个固件函数,测试函数通过参数名引用它,pytest 会自动注入。
  import pytest

  @pytest.fixture
  def sample_data():
      return {"name": "Alice", "age": 30}

  def test_user_age(sample_data):
      assert sample_data["age"] == 30
  
  • 生命周期管理:固件可以有设置和清理逻辑。使用 yield 代替 returnyield 之前的代码是设置,之后的代码是清理(如关闭文件、断开数据库连接)。即便测试失败,清理也会执行。
  @pytest.fixture
  def temp_file():
      f = open("temp.txt", "w")
      yield f
      f.close()
  
  • 作用域控制:通过 scope 参数指定固件的复用范围(functionclassmodulesession),避免重复创建开销大的资源。
  • 实际价值:固件让测试依赖变得显式、可复用,不再需要在每个测试里复制粘贴初始化代码。测试代码更干净,也更易维护。

参数化

当一个测试逻辑需要对多组输入输出进行验证时,pytest 的 @pytest.mark.parametrize 装饰器可以成倍减少重复代码。

  • 基本用法:传入参数名和一组值,pytest 会为每个组合生成一个独立的测试用例。
  @pytest.mark.parametrize("a, b, expected", [
      (1, 2, 3),
      (0, 0, 0),
      (-1, 1, 0),
  ])
  def test_add(a, b, expected):
      assert add(a, b) == expected
  

这样一次运行会得到三个测试结果,失败时会明确告诉你是哪组数据出了问题。

  • 组合参数化:可以对多个参数独立参数化,pytest 会生成所有可能的组合。
  • 与固件配合:参数化的值也可以来自固件,实现更灵活的数据驱动测试。
  • 实际好处:用数据表驱动测试覆盖多种场景,代码量少,覆盖度高,新增测试用例只需加一行数据。

这四项能力构成了 pytest 日常使用的基础。再加上丰富的插件生态(如 pytest-cov 统计覆盖率、pytest-mock 增强模拟、pytest-django 集成 Django),pytest 可以优雅地支撑从小脚本到大型项目的测试需要。