pin_drop当前位置:知识文库 ❯ 图文
Python pytest 框架完全指南 - 高效测试最佳实践
一、pytest 框架概述
pytest 是 Python 生态中最流行的第三方测试框架,以其简洁的语法、强大的功能和丰富的插件生态而广受开发者喜爱。与标准库的 unittest 相比,pytest 具有以下显著优势:
-
简洁的语法:无需继承任何基类,直接编写函数即可成为测试
-
强大的断言:使用原生 assert 语句,自动提供详细的失败信息
-
Fixture 系统:灵活的依赖注入机制,管理测试资源
-
丰富的插件:超过800个社区插件,覆盖各种测试场景
-
兼容 unittest:可以直接运行 unittest 编写的测试用例
二、核心语法与安装配置
1. 安装 pytest
代码示例
# 使用 pip 安装
pip install pytest
# 验证安装
pytest --version
# 安装常用插件
pip install pytest-cov pytest-xdist pytest-html2. 命名约定
pytest 使用以下命名约定来自动发现测试:
-
测试文件:
test_*.py或*_test.py -
测试函数:以
test_开头的函数 -
测试类:以
Test开头的类(不能有 __init__ 方法)
三、基本用法与断言
1. 最简单的测试
代码示例
# test_simple.py
def add(a, b):
return a + b
def test_add():
"""最简单的 pytest 测试"""
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
def test_add_negative():
"""测试负数相加"""
assert add(-2, -3) == -52. 强大的断言重写
pytest 最大的特点之一是使用原生的 assert 语句,并在测试失败时提供详细的上下文信息:
代码示例
def test_assert_examples():
"""pytest 断言示例"""
# 相等断言
assert [1, 2, 3] == [1, 2, 3]
# 包含断言
assert "hello" in "hello world"
# 异常断言
with pytest.raises(ZeroDivisionError):
1 / 0
# 异常信息断言
with pytest.raises(ValueError, match="must be positive"):
raise ValueError("value must be positive")
# 警告断言
with pytest.warns(DeprecationWarning):
import warnings
warnings.warn("deprecated", DeprecationWarning)3. 测试类和分组
代码示例
class TestStringMethods:
"""使用测试类组织相关测试"""
def test_upper(self):
assert "hello".upper() == "HELLO"
def test_isupper(self):
assert "HELLO".isupper()
assert not "Hello".isupper()
def test_split(self):
s = "hello world"
assert s.split() == ["hello", "world"]
with pytest.raises(TypeError):
s.split(2)
class TestListMethods:
"""列表相关测试"""
def test_append(self):
lst = [1, 2]
lst.append(3)
assert lst == [1, 2, 3]
def test_pop(self):
lst = [1, 2, 3]
assert lst.pop() == 3
assert len(lst) == 24. 运行测试
代码示例
# 运行当前目录及子目录下所有测试
pytest
# 运行指定文件
pytest test_simple.py
# 运行指定测试函数
pytest test_simple.py::test_add
# 运行指定测试类中的方法
pytest test_simple.py::TestStringMethods::test_upper
# 显示详细输出
pytest -v
# 遇到第一个失败就停止
pytest -x
# 显示局部变量信息
pytest -l
# 显示测试执行时间
pytest --durations=10四、Fixture 机制详解
Fixture 是 pytest 最强大的特性之一,用于管理测试的前置准备和后置清理工作。
代码示例
import pytest
@pytest.fixture
def sample_data():
"""最简单的 fixture"""
return {"name": "张三", "age": 25, "city": "北京"}
def test_sample_data(sample_data):
"""通过函数参数注入 fixture"""
assert sample_data["name"] == "张三"
assert sample_data["age"] == 25
@pytest.fixture
def db_connection():
"""带有 setup 和 teardown 的 fixture"""
# setup 阶段
print("\n连接数据库...")
connection = {"status": "connected"}
yield connection # 返回给测试使用
# teardown 阶段
print("\n断开数据库连接...")
connection["status"] = "disconnected"
def test_db_query(db_connection):
assert db_connection["status"] == "connected"
@pytest.fixture(scope="module")
def shared_resource():
"""module 级别的 fixture,整个模块只执行一次"""
resource = {"data": "shared"}
yield resource提示:fixture 的 scope 参数可以是 function(默认)、class、module、package、session,决定了 fixture 的执行频率。
五、标记与命令行参数
1. 使用标记分组测试
代码示例
import pytest
@pytest.mark.slow
def test_long_running():
"""标记为慢速测试"""
import time
time.sleep(2)
@pytest.mark.skip(reason="功能尚未实现")
def test_not_implemented():
pass
@pytest.mark.skipif(True, reason="仅在Linux运行")
def test_linux_only():
pass
@pytest.mark.xfail(reason="已知会失败的测试")
def test_known_failure():
assert False
# 运行特定标记的测试
# pytest -m slow # 只运行 slow 标记的测试
# pytest -m "not slow" # 跳过 slow 标记的测试2. conftest.py 共享配置
conftest.py 文件用于在多个测试文件之间共享 fixture 和配置:
代码示例
# conftest.py
import pytest
@pytest.fixture
def mock_user():
"""所有测试文件都可以使用的共享 fixture"""
return {"id": 1, "username": "testuser", "role": "admin"}
# pytest.ini 配置文件示例
# [pytest]
# markers =
# slow: marks tests as slow
# integration: marks tests as integration tests
# addopts = -v --tb=short练习1
为一个用户认证模块(包含登录、注册、密码验证功能)编写完整的 pytest 测试用例,使用 fixture 来管理测试数据。
练习2
创建一个 conftest.py 文件,定义不同作用域的 fixture(function、module、session),并在测试中验证它们的执行顺序。
六、课程小结
-
原生 assert 断言:pytest 使用原生 assert 并提供详细的失败信息
-
Fixture 依赖注入:通过函数参数传递,支持多种作用域
-
丰富的标记系统:支持 skip、xfail、自定义标记等
-
conftest.py 共享:轻松在测试文件间共享 fixture 和配置
-
强大的命令行:丰富的命令行参数满足不同测试需求
常见问题
pytest 和 unittest 有什么区别?
pytest 使用原生 assert 而非 unittest 的 assertEqual 等方法,语法更简洁;pytest 不需要继承基类,直接写函数即可;pytest 的 fixture 系统比 unittest 的 setUp/tearDown 更灵活;pytest 拥有丰富的插件生态。
如何在 pytest 中使用 unittest 的测试用例?
pytest 完全兼容 unittest,只需直接运行 pytest 命令即可,pytest 会自动发现并执行继承自 unittest.TestCase 的测试类,无需任何修改。
fixture 的 yield 和 return 有什么区别?
return 只返回数据给测试,yield 会将 yield 之前的代码作为 setup,yield 之后的代码作为 teardown。yield 适合需要清理资源的场景,如关闭数据库连接、删除临时文件等。
如何查看 pytest 支持的所有命令行参数?
运行 pytest --help 可以查看所有命令行参数。常用的包括 -v(详细输出)、-x(遇到失败停止)、--tb=short(简短 traceback)、-q(静默模式)、-k(按名称过滤测试)等。
本文涉及AI创作
内容由AI创作,请仔细甄别