蒙珣的博客

活好当下,做好今天该做的事情。

0%

pytest-Allure

Allure报告结构

  • Overview:整体数据显示。

  • Suites:用例集合,按照套件和类分组的已执行测试的标准结构表示形式。

  • Behaviors:对于行为驱动的方法,此选项卡根据Epic、Feature和Story标记对测试结果进行分组。

  • Categories:“类别”选项卡提供了创建自定义缺陷分类以应用测试结果的方法。

  • Graphs:用图表显示测试数据中收集的不同统计数据,状态分解或严重性和持续时间图。

  • Packages:软件包选项卡表示测试结果的树状布局,按不同的包名分组。

  • Timeline:时间轴选项卡可视化测试执行的回顾,allure适配器收集测试的精确时间,在这个选项卡上,它们相应地按照顺序或并行的时间结构排列。

Allure安装

1
pip install allure-pytest
  1. 下载 allure ZIP包 https://github.com/allure-framework/allure2/releases
  2. pip install pytest-allure
  3. vim ~/.zshrc 并在最后一行添加环境变量 export PATH="/Users/william/DYJ/Tools/allure-2.7.0/bin:$PATH"
  4. 使环境变量生效 source ~/.zshrc
  5. 验证 allure --version

Allure基本用法

  • @allure.epic(): 项目名称
  • @allure.feature(): 模块名称,功能点描述
  • @allure.story(): 接口名称
  • @allure.title(): 测试用例标题(适用于一个方法对应一个用例)
  • allure.dynamic.title: 测试用例标题(适用于一个方法对应多个用例,用于数据驱动情况)
  • @allure.testcase(): 关联测试用例系统里面的用例
  • @allure.issue(): 关联缺陷管理系统里面的链接
  • @allure.description: 测试用例的描述
  • @allure.step(): 测试用例的步骤
  • @allure.severity(): 用例的等级(block、critical、normal、minor、trivial)
  • @allure.link(): 定义一个链接,在测试报告中展现
  • @allure.attachment(): 为测试报告添加附件

Allure epic/feature/story/title

  1. 编辑./testcase/alluredemo/test_allure.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import pytest
    import allure

    @allure.epic("接口项目名称:xx在线接口测试")
    @allure.feature("接口模块名称:IVR接口")
    class TestApi:

    @allure.story("接口名称:常规请求")
    @allure.title("@allure.title 测试用例1")
    def test_allure_01(self):
    print("test_allure_01")

    @allure.title("@allure.title 测试用例2")
    def test_allure_02(self):
    print("test_allure_02")
  2. 修改pytest.ini文件中的addopts参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    [pytest]
    #--html ./report/report.html,reruns 失败重跑次数
    # addopts = -vs -n=2 -reruns 2 --html ./report/report.html
    # 生成json格式的allure报告,并删除上一次的报告
    addopts = -vs --alluredir=reports/temps --clean-alluredir
    # 指定 pytest 搜索测试文件的路径。pytest 将在 ./interfaceCase 目录下搜索可执行文件
    testpaths =
    ./testcase/alluredemo
    # 指定 pytest 应该匹配的测试文件模式。pytest 将会运行所有以 test_ 为开头的 python 文件
    python_files = test_*.py
    # 指定 pytest 应该匹配的测试类名模式。pytest 将会运行所有以 Test 开头的类
    python_classes = Test
    # 指定 pytest 应该匹配的测试函数模式。pytest 将会运行所有以 Test 开头的函数
    python_functions = test
    # 用于为测试用例添加标记。使用方法: @pytest.mark.smoke pytest -m "smoke [or usermanage]"
    markers =
    smoke : Smoke Testing Module
    userManage : User Management Module
    productManage : 商品管理
  3. main.py文件

    1
    2
    3
    4
    5
    6
    7
    import os
    import pytest

    if __name__ == '__main__':
    pytest.main()
    time.sleep(1) # 生成报告需要一点时间
    os.system('allure generate ./reports/temps -o ./reports/allures --clean')
    • allure generate 固定写法
    • ./reports/temps: 临时的 json 格式报告的路径
    • -o: 输出 output
    • ./reports/allure: 生成的 allure 报告的路径
    • --clean: 清空./report 路径原来的报告
  4. 结果

Allure severity/description

  • Blocker
  • Critical
  • Normal
  • Minor
  • Trivial

@allure.severity(allure.serverity_level.BLOCKER)

这个装饰器既可以修饰方法,也可以修饰类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pytest
import allure

@allure.epic("接口项目名称:xx在线接口测试")
@allure.feature("接口模块名称:IVR接口")
class TestApi:

@allure.story("接口名称:常规请求")
@allure.title("@allure.title 测试用例1") # 单次的用例标题
@allure.description("@allure.description: 测试用例描述") # 单次的用例描述
@allure.severity(allure.severity_level.BLOCKER) # 单次的用例优先级
def test_allure_01(self):
print("test_allure_01")

@allure.title("@allure.title 测试用例2")
def test_allure_02(self):
allure.dynamic.title("allure.dynamic.title") # 用于数据驱动的标题
allure.dynamic.description("allure.dynamic.description") # 用于数据驱动的用例描述
allure.dynamic.severity(allure.severity_level.BLOCKER) # 用于数据驱动的用例优先级
print("test_allure_02")

结果:

  • @allure.description(): 用例描述
  • @allure.link(url, name=name): 接口地址
  • @allure.issue(url, name=name): BUG链接
  • @allure.testcase(url, name=name): 测试用例地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pytest
import allure

@allure.epic("接口项目名称:xx在线接口测试")
@allure.feature("接口模块名称:DM接口")
class TestApi:

@allure.story("接口名称:数据驱动测试")
@pytest.mark.parametrize("test_case_title, link",
[["allure.dynamic.title 测试用例1", "127.0.0.1"],
["allure.dynamic.title 测试用例2", "127.0.0.1"],
["allure.dynamic.title 测试用例3", "127.0.0.1"]])
def test_allure_03(self, test_case_title, link, user_fixture):
allure.dynamic.title(test_case_title)
allure.dynamic.severity(allure.severity_level.BLOCKER)
allure.dynamic.description(test_case_title)
allure.dynamic.link(url=link, name="API URL")
# 测试用例步骤
for i in range(1, 10):
with allure.step("测试用例步骤" + str(i) + ""):
print("步骤" + str(i) + "执行脚本")

结果:

使用YAML作为数据驱动

  • allure.attach(file_path, name=None, attachment_type=None): 附件

attachment_type=allure.AttachmentType.TEXT类型:

  1. TEXT - 文本内容。用于附加简单的文本信息。
  2. PNG - PNG 图片格式。用于附加截图或其他 PNG 图片。
  3. JPG - JPG 图片格式。用于附加 JPG 格式的图片。
  4. GIF - GIF 图片格式。用于附加 GIF 图片。
  5. HTML - HTML 内容。用于附加 HTML 格式的内容,可以在报告中渲染为富文本。
  6. XML - XML 格式内容。用于附加 XML 文件或内容。
  7. JSON - JSON 格式内容。用于附加 JSON 文件或内容。
  8. CSV - CSV 格式内容。用于附加 CSV 文件或内容。
  9. TXT - 文本文件。与 TEXT 类似,但更强调是文件形式。

test_allure.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-
name: 获取token接口
description: 接口描述
severity: BLOCKER
request:
method: get
url_name: "bing search"
url: https://cn.bing.com/search?/
data:
q: "安娜卡列尼娜"
validate: None

-
name: 获取token接口
description: 接口描述
severity: CRITICAL
request:
method: get
url_name: "bing search"
url: https://cn.bing.com/search?/
data:
q: "平凡的世界"
validate: None

test_allure.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import json
import pytest
import allure
import yaml
import requests
import os

class YamlUntil:
def __init__(self, yaml_file):
self.yaml_file = yaml_file

def read_yaml(self):
with open(self.yaml_file, 'r', encoding='utf-8') as f:
data = yaml.load(f, Loader=yaml.FullLoader)
return data

def get_severity_level(severity_string):
severity_mapping = {
"BLOCKER": allure.severity_level.BLOCKER,
"CRITICAL": allure.severity_level.CRITICAL,
"NORMAL": allure.severity_level.NORMAL,
}
# 通过get获取对应的值,默认为...NORMAL
return severity_mapping.get(severity_string, allure.severity_level.NORMAL)


@allure.epic("接口项目名称:xx在线接口测试")
@allure.feature("接口模块名称:DM接口")
class TestApi:

yaml_path = os.getcwd() + "/testcase/alluredemo/test_allure.yaml"
yaml_file = YamlUntil(yaml_path).read_yaml()

@allure.story("接口名称:数据驱动测试")
@pytest.mark.parametrize("caseinfo", yaml_file)
def test_allure_03(self, caseinfo, user_fixture):
#print(caseinfo)
allure.dynamic.title(caseinfo["name"])
severity_level = get_severity_level(caseinfo["severity"])
#print(severity_level)
allure.dynamic.severity(severity_level)
allure.dynamic.description(caseinfo["description"])
allure.dynamic.link(url=caseinfo["request"]["url"], name=caseinfo["request"]["url_name"])

# allure.attach 可以二次封装
allure.attach(body=caseinfo["request"]["url"], name="请求地址: ", attachment_type=allure.attachment_type.TEXT)
allure.attach(body=caseinfo["request"]["method"], name="请求方式: ", attachment_type=allure.attachment_type.TEXT)
data = caseinfo["request"]["data"]
allure.attach(body=json.dumps(data), name="请求数据: ", attachment_type=allure.attachment_type.TEXT)
res = requests.get(url=caseinfo["request"]["url"], params=data)
allure.attach(body=res.text, name="响应数据", attachment_type=allure.attachment_type.TEXT)

# 测试用例步骤
for i in range(1, 10):
with allure.step("测试用例步骤" + str(i) + ""):
print("步骤" + str(i) + "执行脚本")

结果:

Reference

[1] https://allurereport.org/docs/

[2] https://zhuanlan.zhihu.com/p/555114726