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将运行每个元组的所有参数值组合,并对每组参数值调用测试函数一次。
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 的参数化的具体长数据
@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读取的数据是字符串,如:
"{'url': 'http://**-ui.iot4-qa-group.orgapp.com/login?next=%2Frecipe', 'title': None, 'referer_url': None, 'referer_url_text': None}"
需要将这个字符串转成字典格式,以下是示例代码:
import astdata = "{'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 测试报告框架中的一个装饰器,用于将动态生成的测试步骤和附件添加到测试报告中,例子:
import alluredef 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")
实际代码:
@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 Noneelse:allure.dynamic.story("巡检通过的链接")allure.dynamic.title(url)
5.description_html
在allure报告case的描述通过一个html表格展示redis读取的数据,定义一个函数 format_table,代码如下:
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.完整代码
# 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 Noneelse: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 htmlif __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装饰器方法介绍