核心技术堆栈:pytest、allure
pytest、allure框架使用demo(一)
pytest、allure-commandline下载、安装、配置
- pip install pytest
- pip install allure-pytest
- allure-commandline下载地址,选择合适的包,下载zip包
- 解压包,把bin目录加入到PATH环境变量
- allure --version 检查是否成功
pytest.ini
[pytest]
;在你当前的这个相对同级的目录中找符合 test开头py文件(或者再往下层找),Test开头的类,test开头的函数
python_files = test*.py
python_classes = Test*
python_functions = test*
;要执行的测试用例的文件夹
testpaths = ../fixture
; --disable-warnings将警告不显示
; -v 让pytest的输出结果更加详细
; -s 开启终端(控制台/输入台)的交互, 如果程序执行的过程中需要控制台输入,但是没有加-s参数,那么会报错
; -k 筛选出名称包含某字符串的用例运行
; 例:-k 0401 函数名称中包含0401的测试函数
; -m 是对pytest.mark标记的用例名进行筛选,多个参数中间可以使用运算符or and not
; 例:addopts = -v -s -m regression and yuyz #执行标签是regression和yuyz的用例
;-v s k 等参数如果放在main方法中嫌太多了,可以放在pytest.ini文件中的addopts中
;addopts = -v -s -k test01 --disable-warnings
addopts = -v -s --disable-warnings
;pytest.mark标记的用例,将警告解决处理
markers =
smoke: Run smoke test
regression: 大回归的测试
yuyz: 个人进行测试的
; --html=report/report.html 同级目录下,创建文件夹
; --self-contained-html 使用pytest-html的时候,可以将html的css文件放在一起,而不再另外生成css文件
conftest.py
import allure
import pytest
from pytest_html import extras
# 定义一个全局变量,用于存储内容
global_data = {}
'''
fixture ,将函数中返回的数据传给用例,当多个用例都需要这个函数/数据的时候,可以将数据放在fixture标记的函数中
fixture函数可以放在conftest文件中也可以放在测试文件中
fixture的数据如果是一个列表。会被视为多个用例,测试函数会多次执行
autouse=True 则每个模块/类/测试函数前置都会执行
scope='module',session,class,常常需要搭配使用autouse,在每个模块中前置或者后置会被执行,scope='function',在每个函数的前置或后置会被执行。
后置执行,需要加yield,每条用例执行完之后会执行yield之后的
module范围,这个模块执行一次
class范围的时候也包括了模块中的函数(在类中执行一次,模块中每个函数都执行),
function则包含了模块中的所有的函数
name='c_fixture',可以自定义名称,名称可以与函数的不一样,被调用的时候使用name
'''
@pytest.fixture(autouse=True, scope='module')
def fixture_data():
print('fixture_data')
yield
print('fixture_data...')
@pytest.fixture()
def fixture_data2():
return [1, 2, 3]
@pytest.fixture(params=['a', 'b', 'c'])
def fixture_data3(request):
return request.param
@pytest.fixture(params=['d', 'e', 'f'], name='p4')
def fixture_data4(request):
return request.param
@pytest.fixture(params=[('输入正确的', {'name': 'zhangsan', 'password': '123456'}, '成功'),
('输入错误用户', {'name': 'zhangsan1', 'password': '123456'}, '失败'),
('输入正确密码', {'name': 'zhangsan', 'password': '1234561'}, '失败')
], name='p5')
def fixture_data5(request):
return request.param
@pytest.fixture()
def set_global_data():
"""设置全局变量,用于关联参数"""
def set_data(key, value):
global_data[key] = value
return set_data
@pytest.fixture()
def get_global_data():
"""从全局变量global_data中取值"""
def get_data(key):
return global_data[key]
return get_data
# 当测试出错的时候,截图
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call): # 利用钩子函数的回调进行判断并且处理
outcome = yield
report = outcome.get_result()
if report.when == 'call':
xfail = hasattr(report, 'wasxfail')
if (report.skipped and xfail) or (report.failed and not xfail):
# if report.outcome != 'passed':
"""失败截图数据"""
image_path = 'D:\workfile\PycharmProjects\\fixture\img\23.png'
with open(image_path, 'rb') as image_file:
allure.attach(image_file.read(), '错误截图', attachment_type=allure.attachment_type.PNG)
test1.py
import allure
import pytest
from pytest_html import extras
test_data5 = [('输入正确的', {'name': 'zhangsan', 'password': '123456'}, '成功'),
('输入错误的', {'name': 'lisi', 'password': '123456'}, '失败'),
('输入没有的', {'name': 'wwwww', 'password': '123456'}, '没有')]
def test_d1():
print('test_d1')
def test_d2():
print('test_d2')
# allure 行为标记,让allure的报告层级鲜明
@allure.epic('用户端')
@allure.feature('用户登录')
class Test01:
@allure.testcase('127.09.34.64:8080')
@allure.issue('127.09.34.64:8081')
@allure.story('用例登录用例1')
@allure.title('执行登录')
@allure.severity('critical') # blocker阻塞 critical严重 normal一般 minor次要 trivial轻微
def test01_1(self):
print('test01_1')
@allure.severity('blocker')
def test01_2(self):
print('test01_2')
@allure.severity('normal')
def test01_3(self, fixture_data2):
with allure.step('步骤test01_3'):
print('步骤1')
print('test01_3')
print(fixture_data2)
@allure.severity('minor')
def test01_4(self, fixture_data3):
print('test01_4')
print(fixture_data3)
assert fixture_data3 == 'a'
'''名称使用自定义的param'''
@allure.severity('critical')
@allure.title('{title}')
@allure.description('原始描述5')
@pytest.mark.parametrize('title,test_input,expected', test_data5)
def test01_5(self, title, test_input, expected):
print('test01_5')
print(test_data5)
@allure.severity('critical')
@allure.description('原始描述')
def test01_6(self):
desc = "<font color='red'>请求URL:</font>{}<Br/>" \
"<font color='red'>请求类型:</font>{}<Br/>" \
"<font color='red'>期望结果:</font>{}<Br/>" \
"<font color='red'>实际结果描述:</font>{}<Br/>" \
.format("http://www.baidu.com", "post", "200", '404')
assert 42 == int(6 * 7)
# 这里断言成功,则会用新的描述方式,断言失败则会用原始描述
allure.dynamic.description(desc)
@allure.severity('critical')
@allure.title('原始标题')
def test_01_7(self):
assert 4 == 2*2
allure.dynamic.title('断言成功,更新标题')
print('其他的比如story epic testcase都是可以用dynamic进行更新的!')
def test01_add_img(self, extra): # pytest默认的外部数据列表
def image_to_base64(image_path):
import base64
"""这个函数是将图片转化为base64数据"""
with open(image_path, "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
return encoded_string.decode('utf-8')
# 添加图片文件
image_path = 'D:\workfile\PycharmProjects\23.png'
extra.append(extras.jpg(image_path))
# 添加base64格式的图片
base64_data = image_to_base64(image_path)
extra.append(extras.image(base64_data)) # pytest-html添加图片
def test01_allure_add_img(self):
image_path = 'D:\workfile\PycharmProjects\23.png'
with open(image_path, 'rb') as image_file:
allure.attach(image_file.read(), name='图片的名称', attachment_type=allure.attachment_type.PNG)
@allure.epic('管理端')
@allure.feature('用户管理')
class Test02:
@allure.testcase('127.09.123.64:8080')
@allure.issue('127.09.123.64:8081')
@allure.story('用户管理用例1')
@allure.title('管理登录')
@allure.severity('critical')
def test02_1(self):
print('test01_1')
def test02_2(self):
print('test01_2')
@allure.step('步骤1')
def step1():
print('step1')
@allure.step('步骤2')
def step2():
print('step2')
def test_03():
step1()
step2()
run_suite.py
import pytest
# from pytest_html.html_report
testcases_path = DIR_PATH + os.sep + "testcases"
'''
pip install pytest-html
'''
if __name__ == '__main__':
# pytest.main(['-vs', '-k', 'test01_5']) # 运行标签是regression和yuyz的用例,可以将-v -s命令参数放在pytest.ini文件中
# 在main的同级目录下面生成测试报告html, --self-contained-html 可以将html的css文件放在一起(使用pytest-html的时候才使用)
# pytest.main(["--html=report/report.html", "--self-contained-html"])
# --allure-epics=用户端 指定epic进行执行用例
# --allure-features=f1,f2
# --allure-stories=s1
# 如果只想进行冒烟测试,只想要验证关键用例,只执行blocker critical级别的用例
pytest.main(['--allure-severities=blocker,critical', '--alluredir', 'allure_result', '--clean-alluredir'])
# --clean-alluredir 每次执行之前清空报告
# pytest.main(['--allure-epics=用户端', '--alluredir', 'allure_result', '--clean-alluredir']) # 获取测试结果,保存allure测试数据
# pytest.main(['-vs', 'testPytest1.py::TestCal::test_div_norm']) # 执行某一个函数
# pytest.main(['-vs', testcases_path, '--alluredir', allure_report_path]) # 执行testcases_path的所有用例
# pytest.main(['-vs', '-m', 'regression']) # 执行标签是regression的用例
# pytest.main(['-vs', '-m', 'not regression']) # 执行标签不是regression的用例
# pytest.main(['-vs', '-m', 'regression or yuyz']) # 执行标签是regression或yuyz的用例
# pytest.main(['-vs', '-m', 'regression and yuyz']) # 执行标签是regression和yuyz的用例
import os
# --clean 让报告可以覆盖
os.system('allure generate --clean ./allure_result -o ./allure_report') # 根据测试数据,生成测试报告html
# os.system('allure serve result') # 生成测试报告,在一个web端上展示
努力追求财富自由,不是为了让自己可以放纵,而是为了让自己在面对自己不想要的选择的时候可以坦然说不,去选择自己喜欢的。