1.pytest.mark.parametrize
pytest.mark.parametrize 是一个pytest的装饰器,它可以用于将参数传递给测试函数。使用 pytest.mark.parametrize 装饰器时,需要在装饰器中指定参数名称和参数值。对于多个参数,可以使用多个装饰器。
下面是一些使用 pytest.mark.parametrize 的示例:
在第一个示例中,test_addition 测试函数将三个参数(x、y 和 expected)作为输入。参数值列表包含三个元组,每个元组都包含一组参数值。pytest将运行每个元组的所有参数值组合,并对每组参数值调用测试函数一次。
在第二个示例中,test_uppercase 函数将两个参数(string 和 expected)作为输入。参数值列表包含两个元组,每个元组都包含一组参数值。pytest将运行每个元组的所有参数值组合,并对每组参数值调用测试函数一次。
python
import pytest
@pytest.mark.parametrize('x, y, expected', [(1, 2, 3), (2, 3, 5), (3, 4, 7)])
def test_addition(x, y, expected):
assert x + y == expected
@pytest.mark.parametrize('string, expected', [('hello world', 'HELLO WORLD'), ('goodbye', 'GOODBYE')])
def test_uppercase(string, expected):
assert string.upper() == expected
按照上面的例子,那么读取redis的list数据赋值给变量detail,装饰器 parametrize('detail_one',detail) 这样就可以把redis的list每条数据传到case里面了。但实际调试发现,allure.title 会显示 parametrize 的参数化,把case标题挤得很不好看:
2.要考虑另一种写法,在 allure.title 不显示 parametrize 的参数化的具体长数据
python
@allure.epic("Org-文档中心")
@allure.feature("页面跳转死链接巡检")
@pytest.mark.parametrize("index", list(range(len(detail))))
def test_read_list(index):
detail_dict_one = ast.literal_eval(detail[index])
parametrize 的参数化不传具体的值,而是传list的元素的数量len,在case里面 detail_dict_one = ast.literal_eval(detail[index]) 获取redis的list的每条数据。报告 allure.title 显示 parametrize 参数化的具体长数据的索引:
3.ast.literal_eval
ast.literal_eval() 方法将该字符串转换为字典格式,ast.literal_eval() 方法是将字符串作为 Python 表达式进行评估,如果字符串可以安全地转换为字典、列表或原始类型,则返回转换后的对象。
python代码从redis的list读取的数据是字符串,如:
python
"{'url': 'http://**-ui.iot4-qa-group.orgapp.com/login?next=%2Frecipe', 'title': None, 'referer_url': None, 'referer_url_text': None}"
需要将这个字符串转成字典格式,以下是示例代码:
python
import ast
data = "{'url': 'http://**-ui.iot4-qa-group.orgapp.com/login?next=%2Frecipe', 'title': None, 'referer_url': None, 'referer_url_text': None}"
converted_data = ast.literal_eval(data)
print(converted_data) # {'url': 'http://**-ui.iot4-qa-group.orgapp.com/login?next=%2Frecipe', 'title': None, 'referer_url': None, 'referer_url_text': None}
4.allure.dynamic
默认 allure 报告上的测试用例标题不设置就是用例名称,现在需要的是,当 pytest.mark.parametrize 使用每个参数值作为入参去调用一次测试函数就生成一条case。
allure 提供了在测试用例执行过程中动态指定标题和描述等标签的方法 ,allure.dynamic 是 Allure 测试报告框架中的一个装饰器,用于将动态生成的测试步骤和附件添加到测试报告中,例子:
python
import allure
def test_devloper_docs():
"""
测试用例1
"""
allure.dynamic.title("动态title")
allure.dynamic.description_html("动态description_html")
allure.dynamic.severity("blocker")
allure.dynamic.feature("动态feature")
allure.dynamic.story("动态story")
allure.dynamic.tag("动态tag")
allure.dynamic.link("https://www.baidu.com/?wd=1", "动态link")
allure.dynamic.issue("https://www.baidu.com/?wd=2", "动态issue")
allure.dynamic.testcase("https://www.baidu.com/?wd=3", "动态testcase")
def test_demo():
"""
测试用例2
"""
allure.dynamic.description("动态description")
实际代码:
python
@pytest.mark.parametrize("index", list(range(len(detail))))
def test_read_list(index):
"""
动态设置描述
"""
# 获取redis的list的每条数据,并把字符串"{}"的数据转成字典格式
detail_dict_one = ast.literal_eval(detail[index])
# 从字典获取对应字典的数据
url = detail_dict_one.get('url')
title = detail_dict_one.get('title').strip() if detail_dict_one.get('title') else detail_dict_one.get('title')
referer_url = detail_dict_one.get('referer_url')
referer_url_text = detail_dict_one.get('referer_url_text').strip() if detail_dict_one.get('referer_url_text') else detail_dict_one.get('referer_url_text')
crawled = detail_dict_one.get('crawled')
spider = detail_dict_one.get('spider')
# 把url转成在allure可以直接点击访问的链接
url_link = f"<a href={url}>{url}</a>"
referer_url_link = f"<a href={referer_url}>{referer_url}</a>"
# 定义一个函数html的表格,在用例描述那里展示redis的数据
description_html = format_table(url_link, title, referer_url_link, referer_url_text, crawled, spider)
allure.dynamic.description_html(description_html)
# 把case.title进行分类,归类到不同的story下面,方便查看
if "swagger" in url:
allure.dynamic.story("不需校验的链接")
allure.dynamic.title(url)
pytest.skip("该链接为swagger-json文档,不属于校验范围")
elif title == "该页面不存在":
allure.dynamic.story("链接跳转后该页面不存在")
allure.dynamic.title(url)
assert title != "该页面不存在"
elif referer_url_text is not None and title is None:
allure.dynamic.story("链接跳转后该页面标题为None")
allure.dynamic.title(url)
assert title is not None
else:
allure.dynamic.story("巡检通过的链接")
allure.dynamic.title(url)
5.description_html
在allure报告case的描述通过一个html表格展示redis读取的数据,定义一个函数 format_table,代码如下:
python
def format_table(link, title, referer_url, referer_url_text, crawled, spider):
# 定义HTML样式
style = """
<style>
table {
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid black;
text-align: left;
padding: 8px;
}
th {
background-color: #dddddd;
}
</style>
"""
# 定义表格内容
table_content = f"""
<table>
<tr>
<td>url</td>
<td>{link}</td>
</tr>
<tr>
<td>title</td>
<td>{title}</td>
</tr>
<tr>
<td>referer_url</td>
<td>{referer_url}</td>
</tr>
<tr>
<td>referer_url_text</td>
<td>{referer_url_text}</td>
</tr>
<tr>
<td>crawled</td>
<td>{crawled}</td>
</tr>
<tr>
<td>spider</td>
<td>{spider}</td>
</tr>
</table>
"""
# 将样式和表格内容拼接起来
html = f"{style}{table_content}"
# 返回HTML代码
return html
# 定义一个函数html的表格,在用例描述那里展示redis的数据
description_html = format_table(url_link, title, referer_url_link, referer_url_text, crawled, spider)
allure.dynamic.description_html(description_html)
Description 表格样式:
6.完整代码
python
# coding=utf-8
import pytest
import allure
import os
import ast
from _redis import operate_redis
# 使用lrange()方法从左到右检索整个列表并将其存储在名为detail的变量中
detail = operate_redis().find_redis_list("lrange","developer-docs:items")
@allure.epic("org-文档中心")
@allure.feature("页面跳转死链接巡检")
@pytest.mark.parametrize("index", list(range(len(detail))))
def test_read_list(index):
"""
动态设置描述
"""
# 获取redis的list的每条数据,并把字符串"{}"的数据转成字典格式
detail_dict_one = ast.literal_eval(detail[index])
# 从字典获取对应字典的数据
url = detail_dict_one.get('url')
title = detail_dict_one.get('title').strip() if detail_dict_one.get('title') else detail_dict_one.get('title')
referer_url = detail_dict_one.get('referer_url')
referer_url_text = detail_dict_one.get('referer_url_text').strip() if detail_dict_one.get('referer_url_text') else detail_dict_one.get('referer_url_text')
crawled = detail_dict_one.get('crawled')
spider = detail_dict_one.get('spider')
# 把url转成在allure可以直接点击访问的链接
url_link = f"<a href={url}>{url}</a>"
referer_url_link = f"<a href={referer_url}>{referer_url}</a>"
# 定义一个函数html的表格,在用例描述那里展示redis的数据
description_html = format_table(url_link, title, referer_url_link, referer_url_text, crawled, spider)
allure.dynamic.description_html(description_html)
# 把case.title进行分类,归类到不同的story下面,方便查看
if "swagger" in url:
allure.dynamic.story("不需校验的链接")
allure.dynamic.title(url)
pytest.skip("该链接为swagger-json文档,不属于校验范围")
elif title == "该页面不存在":
allure.dynamic.story("链接跳转后该页面不存在")
allure.dynamic.title(url)
assert title != "该页面不存在"
elif referer_url_text is not None and title is None:
allure.dynamic.story("链接跳转后该页面标题为None")
allure.dynamic.title(url)
assert title is not None
else:
allure.dynamic.story("巡检通过的链接")
allure.dynamic.title(url)
def format_table(link, title, referer_url, referer_url_text, crawled, spider):
# 定义HTML样式
style = """
<style>
table {
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid black;
text-align: left;
padding: 8px;
}
th {
background-color: #dddddd;
}
</style>
"""
# 定义表格内容
table_content = f"""
<table>
<tr>
<td>url</td>
<td>{link}</td>
</tr>
<tr>
<td>title</td>
<td>{title}</td>
</tr>
<tr>
<td>referer_url</td>
<td>{referer_url}</td>
</tr>
<tr>
<td>referer_url_text</td>
<td>{referer_url_text}</td>
</tr>
<tr>
<td>crawled</td>
<td>{crawled}</td>
</tr>
<tr>
<td>spider</td>
<td>{spider}</td>
</tr>
</table>
"""
# 将样式和表格内容拼接起来
html = f"{style}{table_content}"
# 返回HTML代码
return html
if __name__ == '__main__':
# pytest.main(["-s","allure-test.py"])
'''
-q: 安静模式, 不输出环境信息
-v: 丰富信息模式, 输出更详细的用例执行信息
-s: 显示程序中的print/logging输出
'''
pytest.main(['-s', '-q', '--clean-alluredir', '--alluredir=docs_report/report/allure-results'])
os.system(r"allure generate docs_report/report/allure-results/ -o docs_report/report/allure-report --clean")
7.allure装饰器方法介绍