Pytest 是用于测试 Python 应用的 Python 库。
官方文档:Full pytest documentation — pytest documentation
安装:
pip install pytest
pytest 测试发现约定规范
如果未指定任何参数,则在testpaths(如果已配置)或当前目录中的位置搜索测试文件。 另外,命令行参数可以在目录,文件名或节点 ID 的任何组合中使用。
pytest 在所选目录中查找test_*.py或*_test.py文件。所有的单测文件名都需要满足test_*.py格式或*_test.py格式。
在选定的文件中,pytest 在类之外查找带前缀的测试函数,并在带前缀的测试类中查找带前缀的测试方法(无__init__()方法)。
在单测文件中,测试类以Test开头,并且不能带有 __init__ 方法。注意:定义class时,需要以大写T开头。
在单测类中,可以包含一个或多个test_开头的函数。
注意:测试函数名必须要以test开头。
命令中参数:
指令含义 | 指令 |
---|---|
用于详细显示日志信息 | -v |
测试结果的简单统计 | -rA |
只显示整体测试结果 | -q |
帮助 | -h |
显示print打印信息 | -s |
输出html格式报告 | –html=path输出路径 |
生成log报告 | –resultlog=./log.txt (6.1 版本之后被删除) |
生成xml报告 | –junitxml=./log.xml |
当错误达到num时,停止测试 | –maxfail=num |
只运行有MARKEXPR(自定义)标记的测试 | -m MARKEXPR |
生成简略的指定需求的报告 | -r option |
运行 pytest
max_min_func.py
def max_value(values):
_max = values[0]
for val in values:
if val > _max:
_max = val
return _max
def min_value(values):
_min = values[0]
for val in values:
if val < _min:
_min = val
return _min
max_min_test.py
import max_min_func
def test_min():
values = [3, 5, 8, 1, 9, 2]
val = max_min_func.min_value(values)
assert val == 1
def test_max():
values = [3, 5, 8, 1, 9, 2]
val = max_min_func.max_value(values)
assert val == 9
test_min()
pytest 不带任何参数,将查看当前工作目录(或其他一些预配置的目录)以及测试文件的所有子目录,并运行找到的测试代码。
运行当前目录中的所有测试文件。
pytest
通过指定名称作为参数来运行特定的测试文件。
pytest max_min_test.py
通过在::字符后提供其名称来运行特定功能。
pytest max_min_test.py::test_max
将上述max_min_test.py中test_max()函数的asset val == 9 改为val == 8,再执行测试代码:
Pytest 跳过
使用跳过装饰器,可以跳过指定的测试。 跳过测试有多种原因。 例如,数据库/在线服务目前不可用,或者跳过了 Windows 上针对 Linux 的特定测试。
将上面max_min_test.py代码改写如下:
import max_min_func
import pytest
@pytest.mark.skip
def test_min():
values = [3, 5, 8, 1, 9, 2]
val = max_min_func.min_value(values)
assert val == 1
def test_max():
values = [3, 5, 8, 1, 9, 2]
val = max_min_func.max_value(values)
assert val == 9
test_min()
pytest 标记
使用标记将测试组织为单元。标记可用于对测试进行分组。 然后使用pytest -m运行一组标记的测试。
marking.py
import pytest
@pytest.mark.a
def test_a1():
assert (1) == (1)
@pytest.mark.a
def test_a2():
assert (1, 2) == (2, 1)
@pytest.mark.a
def test_a3():
assert (1, 2, 3) == (1, 2, 3)
@pytest.mark.b
def test_b1():
assert "falcon" == "fal" + "con"
@pytest.mark.b
def test_b2():
assert "falcon" == f"fal{'con'}"
Pytest 参数化测试
通过参数化测试,可以向断言中添加多个值。 使用@pytest.mark.parametrize标记。
param_test.py
import max_min_func
import pytest
@pytest.mark.parametrize("data, expected", [((2, 3, 1, 4, 6), 1),
((5, -2, 0, 9, 12), -2), ((200, 100, 0, 300, 400), 0)])
def test_min(data, expected):
val = max_min_func.min_value(data)
assert val == expected
@pytest.mark.parametrize("data, expected", [((2, 3, 1, 4, 6), 6),
((5, -2, 0, 9, 12), 12), ((200, 100, 0, 300, 400), 400)])
def test_max(data, expected):
val = max_min_func.max_value(data)
assert val == expected
pytest 夹具
测试需要在一组已知对象的背景下进行。 这组对象称为测试夹具。
func_test.py
def max_value(values):
_max = values[0]
for val in values:
if val > _max:
_max = val
return _max
def min_value(values):
_min = values[0]
for val in values:
if val < _min:
_min = val
return _min
def list_sort(data):
if not isinstance(data, list):
vals = list(data)
else:
vals = data
size = len(vals)
for i in range(0, size):
for j in range(i + 1, size):
if vals[j] < vals[i]:
_min = vals[j]
vals[j] = vals[i]
vals[i] = _min
return vals
if __name__ == '__main__':
aa = list_sort([5, 6, 1, 8])
print(aa)
fix_test.py
import func_test
import pytest
@pytest.fixture
def data():
return [4, 6, 5, 7, 2, 3, 9, 11, -3]
def test_sort(data):
sort_val = func_test.list_sort(data)
assert sort_val == sorted(data)
Pytest 布局
Python 测试可以多种方式组织。 测试可以集成在 Python 包中,也可以放在包外。
外部测试
内部测试
函数数据参数化
方便测试函数对参数的调用:
@pytest.mark.parametrize(argnames,argvalues, indirect=False, ids=None, scope=None)
argnames:参数名
argvalues:参数对应值,可传多个值,类型必须为list [(values1,values2,…),(value1,value2,…)]
pytest 会将定义好的参数列表逐个填入到参数位置中执行代码,有多少个执行多少遍
import pytest
'''
parametrize
'''
class TestFunc(object):
def setup_class(self):
print("---------setup_class----------")
def teardown_class(self):
print("------------teardown_class-------------")
# 传递单参数
@pytest.mark.parametrize("a", [3, 6])
def test_1(self, a):
print("a = %d" % a)
assert a % 3 == 0
# 传递多参数
@pytest.mark.parametrize('a,b', [(0, 3), [1, 2]])
def test_2(self, a, b):
print("%d + %d = %d" % (a, b, a + b))
assert a + b == 3
if __name__ == "__main__":
pytest.main(['-s', '-v', 'parametrize_test.py::TestFunc::test_1'])
pytest.main(['-s', '-v', 'parametrize_test.py::TestFunc::test_2'])
多进程运行CASE
当cases量很多时,运行时间也会变的很长,如果想缩短脚本运行的时长,就可以用多进程来运行。
安装pytest-xdist:
pip install -U pytest-xdist
运行方法:
pytest test_se.py -n NUM
其中NUM填写并发的进程数。
生成HTML报告
安装pytest-html:
pip install pytest-html
使用时直接在命令行pytest命令后面加--html=<文件名字或者路径>.html参数就可以了。
pytest max_min_test.py --html=report.html
上面生成的报告包括html和一个assets文件(里面是报告CSS样式),如果要合成一个文件可以添加下面的参数。
pytest max_min_test.py --html=report.html --self-contained-html
生成XML报告
pytest --junitxml=report.xml
参考博文: