pytest&allure分析redis的数据并动态生成testCase报告

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 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 测试报告框架中的一个装饰器,用于将动态生成的测试步骤和附件添加到测试报告中,例子:

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")

实际代码:

@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,代码如下:

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 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装饰器方法介绍

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-24 14:14:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-24 14:14:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-24 14:14:03       87 阅读
  4. Python语言-面向对象

    2024-01-24 14:14:03       96 阅读

热门阅读

  1. SpringMVC-域对象共享数据

    2024-01-24 14:14:03       48 阅读
  2. 机器学习-PCA降维【手撕】

    2024-01-24 14:14:03       52 阅读
  3. c# MathNet.Numerics 圆拟合使用案例

    2024-01-24 14:14:03       54 阅读
  4. c语言中的sscanf函数

    2024-01-24 14:14:03       46 阅读
  5. SpringBoot如何测试打包部署

    2024-01-24 14:14:03       45 阅读
  6. 蒙特卡洛方法概述

    2024-01-24 14:14:03       55 阅读
  7. Golang中int, int8, int16, int32, int64和uint区别

    2024-01-24 14:14:03       52 阅读
  8. 02_正则表达式的应用

    2024-01-24 14:14:03       49 阅读
  9. Flowable使用docker中MySQL8,Springboot启动出错

    2024-01-24 14:14:03       57 阅读