Pytest 简介与安装使用
Pytest 是一个功能强大且易于使用的 Python 测试框架,用于编写和运行单元测试用例、集成测试和功能测试,对比 unittest 框架,Pytest 的优势非常明显:
- 简单易用:Pytest 的语法简单明了,学习曲线低,它采用了自然的测试用例编写方式,使得编写测试代码变得更加简单和直观。
- 灵活性:Pytest 支持多种测试样式,包括函数式、类式、模块级别的测试,甚至支持测试生成器,而且插件生态非常丰富,可以通过插件来扩展 Pytest 的功能,满足各种测试场景。
- 集成性:Pytest 可以很好地与其他测试工具和框架集成,比如与 Jenkins、Travis CI、Coverage.py 等。它还支持与其他测试框架(如 unittest 和 doctest)协同工作。
- 丰富的输出信息:Pytest 在测试运行过程中提供丰富的输出信息,包括测试结果、失败原因、详细的堆栈跟踪等,便于开发人员定位和修复问题。
官网文档:https://docs.pytest.org/en/8.0.x/
安装命令
bash
pip install pytest
在 Pytest 中,测试用例的编写需要遵循以下规则:
- 测试文件以 test_ 开头或 _test 结尾;
- 测试类以 Test 开头,并且不能带有 init 方法;
- 测试函数以 test_ 开头;
- 断言使用基本的 assert 即可;
pytest 会递归查找当前目录及子目录下的所有以 test_ 开始或者 _test 结尾的 Python 脚本,执行其中符合规则的函数和方法,不需要显示调用,一些常见的运行命令:
Pytest 常用运行命令
bash
# 直接运行文件夹内符合规则的所有用例
pytest folder_name
# 执行某个 Python 文件中的用例
pytest test_file.py
# 执行某个 Python 文件内的某个函数
pytest test_file.py::test_func
# 执行某个 Python 文件内某个测试类的某个方法
pytest test_file.py::TestClass::test_method
# 运行测试时显示标准输出(stdout),允许测试中的 print() 语句直接输出到终端
pytest -s
# 运行测试时显示详细的信息,包括每个测试用例的名称及结果(通过/失败/跳过等),-v 代表 verbose
pytest -v
fixture 设置测试环境
在 Pytest 中,fixture 是一种用于为测试函数提供预设数据或设置测试环境的机制。简单来说,可以使用 fixture 来为测试提供预设数据和设置测试环境的功能。
fixture 通常写在 conftest.py 文件中,并且对应的目录及子目录都可以使用 conftest.py 提供的 fixture,如果存在嵌套 conftest.py 文件,则使用的是最接近的 fixture。定义好 fixture 后,在测试函数中,可以使用同名的参数直接使用,Pytest 会自动注入。
示例:
test/conftest.py
python
import pytest
from app.server.app import app
@pytest.fixture
def client():
app.config["TESTING"] = True
with app.test_client() as client:
yield client
test/internal/handler/test_app_handler.py
python
import pytest
from pkg.response import HttpCode
class TestAppHandler:
def test_completion(self, client):
r = client.post("/app/completion", json={"query": "你好,你是?"})
assert r.status_code == 200
assert r.json.get("code") == HttpCode.SUCCESS
Pytest 参数化测试
在 Pytest 中可以使用 @pytest.mark.parametrize 装饰测试函数,实现使用不同的参数值多次测试运行相同的代码,以覆盖多种测试场景,可以传递 2 个参数,分别是参数名和参数值:
- 参数名 :
query为单个参数,email, password为 2 个参数; - 参数值 :
[None, "你好,你是?"]为单个参数对应的参数列表,[("admin@imooc.com", "123456"), ("hi@imooc.com", "123456")]为多个参数对应的元组参数列表;
使用示例
python
# test/internal/handler/test_app_handler.py
import pytest
from pkg.response import HttpCode
class TestAppHandler:
@pytest.mark.parametrize("query", [None, "你好,你是?"])
def test_completion(self, query, client):
r = client.post("/app/completion", json={"query": query})
assert r.status_code == 200
if query is None:
assert r.json.get("code") == HttpCode.VALIDATE_ERROR
else:
assert r.json.get("code") == HttpCode.SUCCESS
上面这段代码会重复测试两次,第1次传递的 query 值为 None,并执行代码;第2次测试传递的 query 值为"你好,你是?",并根据参数的不同判断测试结果,以检测代码是否正常运行。
04. pytest.ini 配置运行时
在 Pytest 中,基础的配置可以放在 pytest.ini 配置文件中,格式如下:
ini
[pytest]
config_key=config_value
pytest.ini 中支持的配置项非常多,示例如下:
bash
[pytest]
# 设置测试缓存文件存储在 tmp/.pytest_cache 中
cache_dir = tmp/.pytest_cache
# 设置默认的命令行选项
addopts = -v -s
# 指定 Pytest 在哪些文件中查找测试函数
python_files = test_*.py *_test.py
# 指定 Pytest 在哪些类中查找测试方法
python_classes = Test*
# 指定 Pytest 在哪些函数中查找测试用例
python_functions = test_*
配置说明
- cache_dir:自定义 pytest 缓存文件的存储路径,避免默认路径占用项目根目录空间。
- addopts:设置 pytest 默认命令行参数,这里 -v 表示详细输出,-s 表示允许 print 语句在终端显示,每次运行 pytest 时会自动带上这些参数。
- python_files:指定 pytest 识别为测试文件的命名规则,默认是 test_*.py 和 *_test.py。
- python_classes:指定 pytest 识别为测试类的命名规则,默认是 Test* 开头的类。
- python_functions:指定 pytest 识别为测试函数的命名规则,默认是 test_* 开头的函数。