一.参数化实现数据驱动
上一篇介绍了参数化,这篇 说说用参数化实现数据驱动。在有很多测试用例的时候,可以将测试用例都存储在文件里,进行读写调用。本篇主要介绍 csv 文件和 json 文件。
1.读取 csv 文件数据
首先创建 csv 文件,将数据 放在csv文件中。然后读取csv 文件的内容,并将读取的 内容返回
import csv# 读取csv 函数
def get_csv_data():list1 = []# 输入存储csv 文件 的目录file = csv.reader(open(r"D:\python_project\API_Auto\API2\data\x_y.csv", encoding="utf-8"))# 输出 csv 文件对象,需要获取文件对象中的内容,使用for 循环进行遍历# print(file)for i in file:# print(i)list1.append(i)else:# print(list1)return list1
再在测试用例中进行调用上面的函数,得到返回的参数,作为参数
import pytestfrom commons.tools import get_csv_data@pytest.mark.parametrize(["x", "y"], get_csv_data())
def test_001(x, y):print(f"x: {x}")print(f"y: {y}")assert x == y
2.读取json文件数据
思路还是一样,先 创建json文件,将数据放进去
再读取json文件中的数据,并将 读取后的数据作为返回值
# 读取json 数据
def get_json_data():# json 数据可以直接读取file = open(r"D:\python_project\API_Auto\API2\data\x_y.json", encoding="utf-8")content = file.read()print(content) # 类型是字符串 “[[1,2],[1,3],[2,3],[5,10],[2,2]]”,有引号不能直接用,需要去掉引号:eval()l = eval(content)# print(l)# print(type(l)) # <class 'list'>return l
在 调用这个方法来得到返回值
# 读取data 目录下的x_y json数据格式的测试用例import pytestfrom commons.tools import get_json_data@pytest.mark.parametrize(["x", "y"], get_json_data())
def test_002(x, y):print(f"x: {x}")print(f"y: {y}")assert x == y
二.fixture
fixture 的主要作用是固定测试环境。在执行用例时,执行 用例之前,执行完用例之后的操作就可以用fixture
1.fixture 创建
定义一个函数,然后加上yield 关键字,再加上pytest 框架装饰器就成了fixture,下面的func,func1都是fixture,func比func1多了一个返回值666
@pytest.fixture()
def func():print("用例执行之前")yield 666print("用例执行之后")@pytest.fixture()
def func1():print("用例执行之前")yield print("用例执行之后")
2.fixture调用
fixture默认是不会自动调用的 ,需要在形参处调用fixture名
# 调用fixture
def test_001(func):print(f"获取fixture:{func}")assert 1 == 1def test_002():assert 1 == 2class TestAAA:# 调用fixturedef test_003(self, func):assert 1 == 1# 获取func 的返回值666print(f"获取fixture:{func}")def test_004(self):assert 1 == 2
输出结果为:
PS D:\python_project\API_Auto\API2> pytest -k test_z1_fixture定义和使用.py
================================================================= test session starts =================================================================
platform win32 -- Python 3.10.6, pytest-8.3.5, pluggy-1.5.0 -- C:\Users\18481\AppData\Local\Programs\Python\Python310\python.exe
cachedir: .pytest_cache
rootdir: D:\python_project\API_Auto\API2
configfile: pytest.ini
plugins: allure-pytest-2.13.5, result-log-1.2.2
collecting ... [[1,2],[1,3],[2,3],[5,10],[2,2]
]
collected 27 items / 23 deselected / 4 selected testcases/test_z1_fixture定义和使用.py::test_001 用例执行之前
获取fixture:666
PASSED用例执行之后testcases/test_z1_fixture定义和使用.py::test_002 FAILED
testcases/test_z1_fixture定义和使用.py::TestAAA::test_003 用例执行之前
获取fixture:666
PASSED用例执行之后testcases/test_z1_fixture定义和使用.py::TestAAA::test_004 FAILED====================================================================== FAILURES =======================================================================
______________________________________________________________________ test_002 _______________________________________________________________________ def test_002():
> assert 1 == 2
E assert 1 == 2testcases\test_z1_fixture定义和使用.py:26: AssertionError
----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------
WARNING pytest_result_log:plugin.py:122 ---------------Start: testcases/test_z1_fixture定义和使用.py::test_002---------------
---------------------------------------------------------------- Captured log teardown ----------------------------------------------------------------
WARNING pytest_result_log:plugin.py:128 ----------------End: testcases/test_z1_fixture定义和使用.py::test_002----------------
__________________________________________________________________ TestAAA.test_004 ___________________________________________________________________ self = <testcases.test_z1_fixture定义和使用.TestAAA object at 0x000002AB6C7CA170>def test_004(self):
> assert 1 == 2
E assert 1 == 2testcases\test_z1_fixture定义和使用.py:35: AssertionError
----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------
WARNING pytest_result_log:plugin.py:122 ----------Start: testcases/test_z1_fixture定义和使用.py::TestAAA::test_004-----------
---------------------------------------------------------------- Captured log teardown ----------------------------------------------------------------
WARNING pytest_result_log:plugin.py:128 -----------End: testcases/test_z1_fixture定义和使用.py::TestAAA::test_004------------
=============================================================== short test summary info ===============================================================
FAILED testcases/test_z1_fixture定义和使用.py::test_002 - assert 1 == 2
FAILED testcases/test_z1_fixture定义和使用.py::TestAAA::test_004 - assert 1 == 2
===================================================== 2 failed, 2 passed, 23 deselected in 0.19s ======================================================
从结果 可以看到,只有test_001和 test_003调用了fixture.
fixture 默认不会自动调用,但是我们也可以通过参数来让他 自动调用 ,就不需要在往形参里传了。只需要将 对应的参数 autouse 的值修改为 True:
@pytest.fixture(autouse=True)
def func():print("用例执行之前")yield 666print("用例执行之后")
def test_001():assert 1 == 1def test_002():assert 1 == 2class TestAAA:def test_003(self):assert 1 == 1def test_004(self):assert 1 == 2
输出结果 为:
PS D:\python_project\API_Auto\API2> pytest -k test_z1_fixture定义和使用.py
================================================================= test session starts =================================================================
platform win32 -- Python 3.10.6, pytest-8.3.5, pluggy-1.5.0 -- C:\Users\18481\AppData\Local\Programs\Python\Python310\python.exe
cachedir: .pytest_cache
rootdir: D:\python_project\API_Auto\API2
configfile: pytest.ini
plugins: allure-pytest-2.13.5, result-log-1.2.2
collecting ... [[1,2],[1,3],[2,3],[5,10],[2,2]
]
collected 27 items / 23 deselected / 4 selected testcases/test_z1_fixture定义和使用.py::test_001 用例执行之前
PASSED用例执行之后testcases/test_z1_fixture定义和使用.py::test_002 用例执行之前
FAILED用例执行之后testcases/test_z1_fixture定义和使用.py::TestAAA::test_003 用例执行之前
PASSED用例执行之后testcases/test_z1_fixture定义和使用.py::TestAAA::test_004 用例执行之前
FAILED用例执行之后====================================================================== FAILURES =======================================================================
______________________________________________________________________ test_002 _______________________________________________________________________ def test_002():
> assert 1 == 2
E assert 1 == 2testcases\test_z1_fixture定义和使用.py:26: AssertionError
----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------
WARNING pytest_result_log:plugin.py:122 ---------------Start: testcases/test_z1_fixture定义和使用.py::test_002---------------
---------------------------------------------------------------- Captured log teardown ----------------------------------------------------------------
WARNING pytest_result_log:plugin.py:128 ----------------End: testcases/test_z1_fixture定义和使用.py::test_002----------------
__________________________________________________________________ TestAAA.test_004 ___________________________________________________________________ self = <testcases.test_z1_fixture定义和使用.TestAAA object at 0x0000017278D0B760>def test_004(self):
> assert 1 == 2
E assert 1 == 2testcases\test_z1_fixture定义和使用.py:35: AssertionError
----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------
WARNING pytest_result_log:plugin.py:122 ----------Start: testcases/test_z1_fixture定义和使用.py::TestAAA::test_004-----------
---------------------------------------------------------------- Captured log teardown ----------------------------------------------------------------
WARNING pytest_result_log:plugin.py:128 -----------End: testcases/test_z1_fixture定义和使用.py::TestAAA::test_004------------
=============================================================== short test summary info ===============================================================
FAILED testcases/test_z1_fixture定义和使用.py::test_002 - assert 1 == 2
FAILED testcases/test_z1_fixture定义和使用.py::TestAAA::test_004 - assert 1 == 2
===================================================== 2 failed, 2 passed, 23 deselected in 0.22s ======================================================
可以看到,这次没有将fixture名放在形参处,所有的测试用例都调用了fixture
3.fixture作用域
fixture 支持五级作用域
- function:函数,方法级别(默认)
像上面未设置作用域,就是默认的function级别,在每个函数执行前触发fixture前置,在每个函数执行后触发fixture后置。
- class:类
- 当类中第一个用例开始执行之前,会触发fixture前置
- 当类中最后一个用例开始执行之后,会触发fixture后置
import pytest@pytest.fixture(scope='class', autouse=True) def func():print("用例执行之前")yield 666print("用例执行之后")def test_001():# print(f"获取fixture:{func}")assert 1 == 1def test_002():assert 1 == 2class TestAAA:def test_003(self):assert 1 == 1# print(f"获取fixture:{func}")def test_004(self):assert 1 == 2
执行结果为:
PS D:\python_project\API_Auto\API2> pytest -k test_z2_fixture的作用域.py ================================================================= test session starts ================================================================= platform win32 -- Python 3.10.6, pytest-8.3.5, pluggy-1.5.0 -- C:\Users\18481\AppData\Local\Programs\Python\Python310\python.exe cachedir: .pytest_cache rootdir: D:\python_project\API_Auto\API2 configfile: pytest.ini plugins: allure-pytest-2.13.5, result-log-1.2.2 collecting ... [[1,2],[1,3],[2,3],[5,10],[2,2] ] collected 27 items / 23 deselected / 4 selected testcases/test_z2_fixture的作用域.py::test_001 用例执行之前 PASSED用例执行之后testcases/test_z2_fixture的作用域.py::test_002 用例执行之前 FAILED用例执行之后testcases/test_z2_fixture的作用域.py::TestAAA::test_003 用例执行之前 PASSED testcases/test_z2_fixture的作用域.py::TestAAA::test_004 FAILED用例执行之后====================================================================== FAILURES ======================================================================= ______________________________________________________________________ test_002 _______________________________________________________________________ def test_002(): > assert 1 == 2 E assert 1 == 2testcases\test_z2_fixture的作用域.py:25: AssertionError ----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------ WARNING pytest_result_log:plugin.py:122 ---------------Start: testcases/test_z2_fixture的作用域.py::test_002---------------- ---------------------------------------------------------------- Captured log teardown ---------------------------------------------------------------- WARNING pytest_result_log:plugin.py:128 ----------------End: testcases/test_z2_fixture的作用域.py::test_002----------------- __________________________________________________________________ TestAAA.test_004 ___________________________________________________________________ self = <testcases.test_z2_fixture的作用域.TestAAA object at 0x000001F49CA9A770>def test_004(self): > assert 1 == 2 E assert 1 == 2testcases\test_z2_fixture的作用域.py:34: AssertionError ----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------ WARNING pytest_result_log:plugin.py:122 -----------Start: testcases/test_z2_fixture的作用域.py::TestAAA::test_004----------- ---------------------------------------------------------------- Captured log teardown ---------------------------------------------------------------- WARNING pytest_result_log:plugin.py:128 ------------End: testcases/test_z2_fixture的作用域.py::TestAAA::test_004------------ =============================================================== short test summary info =============================================================== FAILED testcases/test_z2_fixture的作用域.py::test_002 - assert 1 == 2 FAILED testcases/test_z2_fixture的作用域.py::TestAAA::test_004 - assert 1 == 2 ===================================================== 2 failed, 2 passed, 23 deselected in 0.21s ======================================================
可以看到,对于TestAAA这个类,第一个用例开始执行之前,触发了fixture前置,在、最后一个用例执行之后,触发了fixture后置。而不是想之前每个函数都触发了fixture前置和后置
- module:模块(文件)
- 当模块中第一个用例开始执行之前,会触发fixture前置
- 当模块中最后一个用例开始执行之后,会触发fixture后置
import pytest@pytest.fixture(scope='module', autouse=True) def func():print("用例执行之前")yield 666print("用例执行之后")def test_001():# print(f"获取fixture:{func}")assert 1 == 1def test_002():assert 1 == 2class TestAAA:def test_003(self):assert 1 == 1# print(f"获取fixture:{func}")def test_004(self):assert 1 == 2
执行结果为:
PS D:\python_project\API_Auto\API2> pytest -k test_z2_fixture的作用域.py ================================================================= test session starts ================================================================= platform win32 -- Python 3.10.6, pytest-8.3.5, pluggy-1.5.0 -- C:\Users\18481\AppData\Local\Programs\Python\Python310\python.exe cachedir: .pytest_cache rootdir: D:\python_project\API_Auto\API2 configfile: pytest.ini plugins: allure-pytest-2.13.5, result-log-1.2.2 collecting ... [[1,2],[1,3],[2,3],[5,10],[2,2] ] collected 27 items / 23 deselected / 4 selected testcases/test_z2_fixture的作用域.py::test_001 用例执行之前 PASSED testcases/test_z2_fixture的作用域.py::test_002 FAILED testcases/test_z2_fixture的作用域.py::TestAAA::test_003 PASSED testcases/test_z2_fixture的作用域.py::TestAAA::test_004 FAILED用例执行之后====================================================================== FAILURES ======================================================================= ______________________________________________________________________ test_002 _______________________________________________________________________ def test_002(): > assert 1 == 2 E assert 1 == 2testcases\test_z2_fixture的作用域.py:25: AssertionError ----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------ WARNING pytest_result_log:plugin.py:122 ---------------Start: testcases/test_z2_fixture的作用域.py::test_002---------------- ---------------------------------------------------------------- Captured log teardown ---------------------------------------------------------------- WARNING pytest_result_log:plugin.py:128 ----------------End: testcases/test_z2_fixture的作用域.py::test_002----------------- __________________________________________________________________ TestAAA.test_004 ___________________________________________________________________ self = <testcases.test_z2_fixture的作用域.TestAAA object at 0x0000022EF0DEA8C0>def test_004(self): > assert 1 == 2 E assert 1 == 2testcases\test_z2_fixture的作用域.py:34: AssertionError ----------------------------------------------------------------- Captured log setup ------------------------------------------------------------------ WARNING pytest_result_log:plugin.py:122 -----------Start: testcases/test_z2_fixture的作用域.py::TestAAA::test_004----------- ---------------------------------------------------------------- Captured log teardown ---------------------------------------------------------------- WARNING pytest_result_log:plugin.py:128 ------------End: testcases/test_z2_fixture的作用域.py::TestAAA::test_004------------ =============================================================== short test summary info =============================================================== FAILED testcases/test_z2_fixture的作用域.py::test_002 - assert 1 == 2 FAILED testcases/test_z2_fixture的作用域.py::TestAAA::test_004 - assert 1 == 2 ===================================================== 2 failed, 2 passed, 23 deselected in 0.21s ======================================================
可以看到,在这个文件的第一个用例执行前触发了fixture前置,最后一个用例执行后触发了fixture后置
- 以下2种级别只能在conftest.py文件生效(暂不介绍)
- session:整个项目级别
- package:包级别
4.fixture结合conftest.py文件使用
conftest.py文件在项目中专门用来管理fixture的文件 模块名字是固定不能修改,而且使用fixture不需要导包,会自动检测
首先创建conftest.py文件 ,在文件中创建fixture
然后 就可以在其他文件中调用fixture,并且不需要导包
# conftest.py 文件下的 fixture 可以 直接使用
def test_001(func1):print("测试用例001")def test_002(func2):print("测试用例002")def test_003(func3):print("测试用例003")
测试结果为 :
PS D:\python_project\API_Auto\API2> pytest -k test_z3_fixture结合conftestpy文件使用.py
================================================================= test session starts =================================================================
platform win32 -- Python 3.10.6, pytest-8.3.5, pluggy-1.5.0 -- C:\Users\18481\AppData\Local\Programs\Python\Python310\python.exe
cachedir: .pytest_cache
rootdir: D:\python_project\API_Auto\API2
configfile: pytest.ini
plugins: allure-pytest-2.13.5, result-log-1.2.2
collecting ... [[1,2],[1,3],[2,3],[5,10],[2,2]
]
collected 27 items / 24 deselected / 3 selected testcases/test_z3_fixture结合conftestpy文件使用.py::test_001 这是前置条件1
测试用例001
PASSED这是后置条件1testcases/test_z3_fixture结合conftestpy文件使用.py::test_002 这是前置条件2
测试用例002
PASSED这是后置条件2testcases/test_z3_fixture结合conftestpy文件使用.py::test_003 这是前置条件3
测试用例003
PASSED这是后置条件3========================================================== 3 passed, 24 deselected in 0.13s ===========================================================
三.日志记录Log
记录日志信息主要的作用是,更好的调试监控和排查测试过程中的问题
1.安装日志记录插件
pip install pytest-result-log
2.在pytest.ini配置文件中进行配置
log_file = ./logs/pytest.log
log_file_level = info
log_file_format = %(levelname)-8s %(asctime)s [%(name)s:%(lineno)s] : %(message)s
log_file_date_format = %Y-%m-%d %H:%M:%S; 记录用例执行结果
result_log_enable = 1; 记录用例分割线
result_log_separator = 1;分割线等级
result_log_level_separator = warning;异常信息等级
result_log_level_verbose = info
然后执行 测试用例,就会在目录下生成 logs 目录,打开目录中的文件就可以 查看 log了
WARNING 2025-04-19 18:39:32 [pytest_result_log:122] : ---------Start: testcases/test_z3_fixture结合conftestpy文件使用.py::test_001----------
INFO 2025-04-19 18:39:32 [pytest_result_log:190] : test status is PASSED (testcases/test_z3_fixture结合conftestpy文件使用.py::test_001):
WARNING 2025-04-19 18:39:32 [pytest_result_log:128] : ----------End: testcases/test_z3_fixture结合conftestpy文件使用.py::test_001-----------
WARNING 2025-04-19 18:39:32 [pytest_result_log:122] : ---------Start: testcases/test_z3_fixture结合conftestpy文件使用.py::test_002----------
INFO 2025-04-19 18:39:32 [pytest_result_log:190] : test status is PASSED (testcases/test_z3_fixture结合conftestpy文件使用.py::test_002):
WARNING 2025-04-19 18:39:32 [pytest_result_log:128] : ----------End: testcases/test_z3_fixture结合conftestpy文件使用.py::test_002-----------
WARNING 2025-04-19 18:39:32 [pytest_result_log:122] : ---------Start: testcases/test_z3_fixture结合conftestpy文件使用.py::test_003----------
INFO 2025-04-19 18:39:32 [pytest_result_log:190] : test status is PASSED (testcases/test_z3_fixture结合conftestpy文件使用.py::test_003):
WARNING 2025-04-19 18:39:32 [pytest_result_log:128] : ----------End: testcases/test_z3_fixture结合conftestpy文件使用.py::test_003-----------
四.测试报告 allure
allure报告是一种非常流行的测试报告工具,可以结合多种测试框架集成使用,它提供了一个直观界面,帮助开发人员和测试人员分析测试结果
1.安装 allure
大家可以搜一搜哈,将这个的很多,这里就不多说了。安装完allure后,记得安装第三方 库
pip install allure-pytest
2.使用allure
需要在main.py模块中配置测试报告相关参数
import os
import pytest# 放测试用例的目录
pytest.main(['-sv', r'D:\python_project\API_Auto\API2\testcases', '--clean-alluredir', '--alluredir', './allure_result'])
# 清理旧的测试报告,将allure的测试结果分析生成HTML报告
os.system('allure generate ./allure_result -o ./report --clean')
配置好后右键运行右键main.py模块运行测试用例,然后 找到生成的report目录下的 index.html文件,选一个浏览器打开 就能看到allure报告了
点击 左下角可以切换语言
3.编辑allure
3.1.添加测试步骤
在测试用例上添加 @allure.step(),还可以与参数化之类一起使用
# a.添加测试步骤 @allure.step("test_0001")
@allure.step("test_0001")
@pytest.mark.parametrize(("x", "y"),[[1, 2],[3, 3],[2, 5]]
)
def test_001(x, y):print("AAABBBB")assert x == y
使用后结果为:
3.2.添加测试描述信息
能够给测试用例在报告中记录每一步执行信息
allure.attach()
# b.添加测试描述信息,给测试用例再报告中输出每一步的执行信息 allure.attach()
@allure.step("test_0002")
def test_002():allure.attach("这是002")allure.attach("开始 执行")print("AAABBBB")allure.attach("这是002")allure.attach("执行完毕 ")assert 1 == 1
结果为:
3.3添加严重程度
bug有不同的严重等级:
- blocker 阻塞缺陷(功能未实现,无法下一步)
- critical 严重缺陷(功能点缺失)
- normal 一般缺陷(边界情况,格式错误,默认bug等级)
- minor 次要缺陷(界面错误与ui需求不符)
- trivial 轻微缺陷(必须项无提示,或者提示不规范)
可以在报告中 看到,如果没有特别说明,优先级默认都是normal
@allure.severity(allure.severity_level.CRITICAL)
@allure.severity(allure.severity_level.CRITICAL)
def test_003():print("AAABBBB")assert 1 == 2
测试结果 为
可以看到,优先级变为了设置的