单元测试(unit test),简称UT。本文将介绍在Python项目中,pytest测试框架的安装,配置,执行,测试报告与覆盖率
pytest简介
pytest是一款流行的,简单易上手的单元测试框架,让开发&测试人员专注业务逻辑。
同时pytest有丰富的第三方扩展库,方便生成报告,输出UT覆盖率,支持快速高效的分布式执行。
安装
pytest pypi
pytest-html
pytest-cov
pytest-xdist
更多好用好玩的扩展库,本文将持续更新中……
pip install pytest
pip install pytest-html # 生成html格式UT报告
pip install pytest-cov # 覆盖率
pip install pytest-dist # 分布式执行UT
# 更新第三方库
pip install pytest -U
pip install pytest-html -U
pip install pytest-cov -U
pip install pytest-dist -U
可行的目录结构
Project
ModuleA
ModuleB
pytest.ini # pytest测试框架配置文件
.coveragerc # 覆盖率配置文件
unit_test
__init__.py # 必须要有
conftest.py # pytest 测试套等文件
test_xx.py
配置
PyCharm默认pytest测试框架
中文: 设置
--> 工具
--> Python集成工具
--> 测试
--> 默认测试运行程序: 选择pytest
英文: Settings
--> Tools
--> Python Integrated Tools
--> Testing
--> Default test runner:pytest
pytest.ini
# Project pytest.ini
[pytest]
# 测试用例文件搜索的目录
testpaths = ./tests
# 定义测试标记
markers =
slow: mark test as slow
# 测试用例文件的命名规则
python_files = test_*.py
# 测试函数的命名规则
python_classes = Test
python_functions = test
# 在控制台输出中展示更多的信息 此处 --cov 会导致PyCharm断点调试失败
addopts = -v
# 标记一个测试用例为失败
xfail_strict = true
# 在测试结果中包含原因和语句
setupshow = call, reason, short
# 指定忽略的目录
norecursedirs = .git venv
pytest.ini避坑
pytest.ini options中配置了 --cov
覆盖率相关的命令,会导致PyCharm中 单元测试用例断点调试
失败。
本地开发测试中,pytest.ini中切勿配置!!!
conftest.py
conftest.py是pytest测试框架中特有的文件,可以在此文件中写一些fixture的测试套。
可以写一些前置或后置的测试套,例如连接数据库,初始化环境,或者扫尾的操作。
fixture中声明的函数,测试脚本中可以直接引用,不需要导入, 实现数据共享等
注意点:
- conftest.py 此文件名称是固定的,不能修改
- conftest.py必须与运行的测试用例要在同一个package下,并且要有__init__.py
- 在使用时不需要手动import导入conftest.py,pytest在测试用例执行时会自动去conftest.py文件中查找fixture
- 一个项目下可以有多个conftest.py文件,一般在项目根目录下放一个conftest.py文件起到全局作用;在不同的目录下都可以放置conftest.py文件,作用范围只在该层级以及以下目录生效
# unit_test/conftest.py
# -*- coding: utf-8 -*-
import pytest
# 默认执行, 优先度高
# 例如 可以 将文件路径添加到 sys.path
@pytest.fixture(scope="session") # scope范围: session > module > class > function
def handler():
do_something_pre()
yield
do_something_post()
from your_database_module import create_connection
# fixtures将在测试会话开始时自动检测并可供所有测试文件使用。
#scope="session" 参数表示该fixture的生命周期是整个测试会话期间,因此数据库连接只会创建一次,所有测试都可以共享这个连接
@pytest.fixture(scope="session")
def db_connection():
"""
创建数据库连接的fixture
"""
connection = create_connection("your_database.db")
yield connection # 测试函数可以使用connection
connection.close() # 测试后关闭连接
@pytest.fixture
def shared_data():
# 模拟获取共享数据的过程
data = {
"key1": "value1",
"key2": "value2"
}
return data
# unit_test/test_xx.py
import pytest
def test_database_connection(db_connection): # conftest.py中已经声明db_connection, 无需导入
assert db_connection is not None
# 这里可以进行数据库相关的测试
def test_function(shared_data): # conftest.py中已经声明shared_data, 无需导入
# 使用共享数据
assert shared_data["key1"] == "value1"
assert shared_data["key2"] == "value2"
.coveragerc
覆盖率配置文件,放在unit_test
同级目录, 命令行执行覆盖率统计后,报告在htmlcov目录中。
此配置文件中,可以配置
- 覆盖率统计的代码源目录,
- 忽略的脚本(支持正则写法),
- 忽略的代码行(支持正则写法)。
# .coveragerc
[run]
# 分支
branch = True
# 目录路径
source = .
# 忽略覆盖率统计的文件(夹)
omit =
unit_test/*
# 更多其他不需要统计的文件(夹)
[report]
exclude_lines =
# 以下是一些常见的Python库和测试框架的代码不计算在覆盖率内的行
^def __repr__
^class .*Test$
^if __name__ == .__main__.:
# 你可以根据需要添加更多的排除模式
执行UT
命令行执行
命令行中命令可以配置到 pytest.ini
的 addopts
后,其中 --cov
不建议配置
# -n 分布式执行的线程数量,需要小于系统核数。 例如: -n 7
# --html 指定UT报名的名称
# --self-contained-html 生成单个html文件,包含css样式等
# --cov 执行覆盖率统计,后面可以指定名称,也可以不指定。 指定: --cov=projectName
# --cov-config=.coveragerc 指定配置文件
# --cov-report=html 输出html格式报告
# ubit_test\ UT用例路径
pytest -n 7 --html=report.html --self-contained-html --cov --cov-config=.coveragerc --cov-report=html unit_test\
PyCharm右键执行
右键执行,支持 运行
调试
光标的位置,决定是运行单个测试用例/单个测试类/整个单元测试文件
测试报告report.html
生成的报告中,会显示通过/失败的测试用例。
单击行 可以折叠/打开 用例执行信息
覆盖率报告 htmlcov/index.html
覆盖率会显示全部覆盖率/某个单元测试文件(夹)的覆盖率,涉及合计/执行、未执行/忽略的行等信息