Python测试框架pytest(26)
测试报告Allure
特性
目录
- 1、Environment
- 1.1、添加Environment
- 1.2、解决配置文件被删的问题
- 2、Categories
- 3、allure.step()
- 3.1、@allure.step()方式
- 3.2、with allure.step()方式
- 4、allure.attach
- 5、@allure.description()
- 6、@allure.title()
- 7、@allure.link()
- 8、@allure.issue()
- 9、@allure.testcase()
- 10、@allure.epic()/feature()/story()
- 11、@allure.severity()
1、Environment
Environment 是环境变量,报告默认是没有任何变量参数的,是需要自己配置的。
1.1、添加Environment
通过创建 environment.properties 或者 environment.xml 文件,并把文件存放到测试结果的文件夹(执行脚本时,--alluredir 选项后指定的目录)。
例如:
代码语言:javascript复制pytest -n auto --alluredir=allure
存放在allure文件夹里。
1、添加配置文件
方式一:environment.properties
文件内容:
代码语言:javascript复制Browser=Chrome
Browser.Version=89.0.4389.128
Stand=Test
ApiUrl=127.0.0.1/login
python.Version=3.7.9
方式二:environment.xml
文件内容:
代码语言:javascript复制<environment>
<parameter>
<key>Browser</key>
<value>Chrome</value>
</parameter>
<parameter>
<key>Browser.Version</key>
<value>89.0.4389.128</value>
</parameter>
<parameter>
<key>Stand</key>
<value>Test</value>
</parameter>
<parameter>
<key>ApiUrl</key>
<value>127.0.0.1/login</value>
</parameter>
<parameter>
<key>python.Version</key>
<value>3.7.9</value>
</parameter>
</environment>
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
3、报告展示效果:
注:environment.xml 方式,文件内容含中文时,报告显示正常。
注:environment.properties 方式,文件内容含中文时,报告显示乱码。
1.2、解决配置文件被删的问题
运行 pytest 生成 allure 报告时,有时候需要加参数 --clean-alluredir(清除之前的报告记录),而配置文件(environment.properties 或 environment.xml)也会被删除。
解决方法:
将配置文件(environment.properties 或 environment.xml)存放于项目根目录,运行报告之前,拷贝到报告目录里即可。
项目目录结构:
运行命令(配置文件 environment.properties)
代码语言:javascript复制pytest test_case.py --alluredir=allure --clean-alluredir
cp environment.properties ./allure/environment.properties
allure serve allure
运行命令(配置文件 environment.xml)
代码语言:javascript复制pytest test_case.py --alluredir=allure --clean-alluredir
cp environment.xml ./allure/environment.xml
allure serve allure
2、Categories
Categories 是分类(测试用例结果的分类)
默认情况下,有两类缺陷:
- Product defects 产品缺陷(测试结果:failed)
- Test defects 测试缺陷(测试结果:error/broken)
可以创建自定义缺陷分类,将 categories.json 文件添加到测试结果的目录即可(和 environment.properties 放同一个目录)。
categories.json 参数:
- name:分类名称。
- matchedStatuses:测试用例的运行状态,默认["failed", "broken", "passed", "skipped", "unknown"]。
- messageRegex:测试用例运行的错误信息,默认是 .* ,是通过正则去匹配的。
- traceRegex:测试用例运行的错误堆栈信息,默认是 .* ,是通过正则去匹配的。
categories.json文件内容:
代码语言:javascript复制[
{
"name": "Ignored tests",
"matchedStatuses": ["skipped"]
},
{
"name": "Infrastructure problems",
"matchedStatuses": ["broken", "failed"],
"messageRegex": ".*signOut.*"
},
{
"name": "Outdated tests",
"matchedStatuses": ["broken"],
"traceRegex": ".*FileNotFoundException.*"
},
{
"name": "Product defects",
"matchedStatuses": ["failed"]
},
{
"name": "Test defects",
"matchedStatuses": ["broken"]
}
]
如图所示:测试用例报错时,显示效果
3、allure.step()
在 allure 报告中添加测试用例步骤有两种方式:
1、@allure.step() 这种方式会带上函数的传参和对应的值。
2、with allure.step() 这种方式代码可读性更好一点,但不会带上函数里面的传参和对应的值。
3.1、@allure.step()方式
allure 报告允许对每个测试用例进行非常详细的步骤说明,通过 @allure.step() 装饰器,可以让测试用例在 allure 报告中显示更详细的测试过程。
@allure.step() 只有一个参数,就是 title,输入标题内容,allure 报告上就会显示出来。
1、创建test_allure_step.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
@allure.step("第一步")
def step_one():
pass
@allure.step("第二步")
def step_two_with_nested():
step_three()
@allure.step("第三步")
def step_three():
step_four_with_arguments(123456, 'AllTests')
@allure.step("第四步{0},{arg2}")
def step_four_with_arguments(arg1, arg2):
pass
@allure.step("第五步")
def test_step_five():
step_one()
step_two_with_nested()
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
像Python字符串一样,支持位置参数和关键字参数
如:第四步{0},{arg2}
3.2、with allure.step()方式
1、创建test_allure_step2.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
def one():
pass
def two_with_nested():
three()
def three():
pass
def four(arg1, arg2):
pass
def five():
one()
two_with_nested()
def test_case():
with allure.step("第一步"):
one()
with allure.step("第二步"):
two_with_nested()
with allure.step("第三步"):
three()
with allure.step("第四步"):
four(arg1=123456, arg2='AllTests')
with allure.step("第五步"):
five()
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
执行第四步时,报告没有带上函数里面的传参和对应的值。
4、allure.attach
allure 报告可以显示许多不同类型的附件,这些附件可以补充测试、步骤或装置结果。
可以通过调用:
方式一:
allure.attach(body, name, attachment_type, extension)
参数:
- body:要写入文件的原始内容。
- name:附件名。
- attachment_type:附件类型(是 allure.attachment_type 里面的其中一种)。
- extension:所创建文件的扩展名。
allure.attachment_type提供的附件类型:
方式二:
allure.attach.file(source, name, attachment_type, extension)
参数:
source:包含文件路径的字符串。
(其他参数相同)
1、创建test_allure_attach.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
import allure
@pytest.fixture
def attach_fixture_one(request):
allure.attach('fixture前置操作,添加一个附件txt', 'fixture前置附件', allure.attachment_type.TEXT)
def attach_fixture_two():
allure.attach('fixture后置操作,添加一个附件txt', 'fixture后置附件', allure.attachment_type.TEXT)
request.addfinalizer(attach_fixture_two)
def test_attach_fixture(attach_fixture_one):
print("allure")
def test_attach_fixture_file():
allure.attach('<head></head><body> a page </body>', 'page demo', allure.attachment_type.HTML)
allure.attach.file('./demo.html', 'AllTests demo', attachment_type=allure.attachment_type.HTML)
创建demo.html文件(存放到项目的根目录上)
文件内容:
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>软件测试</title>
</head>
<body>
<h1>AllTests</h1>
</body>
</html>
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
用例test_attach_fixture
用例test_attach_fixture_file,第一个附件为手写的HTML,第二个附件是导入的HTML文件。
5、@allure.description()
添加足够详细的测试用例描述,更加方便查看测试步骤。
三种方式:
代码语言:javascript复制方式一:
@allure.description_html(str):传一个HTML代码组成的字符串
方式二:
@allure.description(str)
方式三:
在测试用例函数下方添加 """ """
1、创建test_allure_description.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
# 方式一
@allure.description_html("""
<h1>Test with some complicated html description</h1>
<table style="width:100%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr align="center">
<td>William</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr align="center">
<td>Vasya</td>
<td>Jackson</td>
<td>94</td>
</tr>
</table>
""")
def test_html_description():
assert True
# 方式二
@allure.description("""
多行测试描述
这是一个@allure.description装饰器
""")
def test_description_from_decorator():
assert 42 == int(6 * 7)
# 方式三
def test_unicode_in_docstring_description():
"""
多行测试描述
assert断言
"""
assert 42 == int(6 * 7)
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
方式一:
方式二:
方式三:
6、@allure.title()
测试用例的标题可以通过特殊的方式变得更易读,标题支持参数占位符并支持动态替换。
示例一:
1、创建test_allure_title.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
import allure
@allure.title("前置操作:登录")
@pytest.fixture
def test_login(request):
params = request.param
name = params["username"]
pwd = params["pwd"]
allure.attach(f"测试用例传的参数{params}")
print(name, pwd, params)
yield name, pwd
@allure.title("登录成功,测试数据:{test_login}")
@pytest.mark.parametrize("test_login", [{"username": "admin", "pwd": "123456"}, {"username": "root", "pwd": "root"}], indirect=True)
def test_login_success(test_login):
name, pwd = test_login
allure.attach(f"账号:{name},密码:{pwd}")
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
示例二:
1、创建test_allure_title2.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
import allure
@allure.title("测试标题参数化: {param1} {param2}")
@pytest.mark.parametrize('param1,param2,expected', [
(2, 2, 4),
(1, 2, 5)
])
def test_with_parameterized_title(param1, param2, expected):
assert param1 param2 == expected
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
7、@allure.link()
链接(访问链接)
装饰器源码:
参数:
- url:跳转的链接。
- name:显示在 allure 报告的名字,如果不传就是显示完整的链接。
类似的装饰器:
Bug链接:@allure.issue()
测试用例链接:@allure.testcase()
1、创建test_allure_link.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
@allure.link('https://www.baidu.com/')
def test_with_link():
pass
@allure.link('https://www.baidu.com/', name='百度一下')
def test_with_named_link():
pass
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
无name参数
有name参数
8、@allure.issue()
链接(Bug链接)
装饰器源码:
调用link(),但link_type=LinkType.ISSUE。
参数:
- url:跳转的链接。
- name:显示在 allure 报告的名字,如果不传就是显示完整的链接。
类似的装饰器:
访问链接:@allure.link()
测试用例链接:@allure.testcase()
1、创建test_allure_issue.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
@allure.issue('https://www.baidu.com/')
def test_with_issue():
pass
@allure.issue('https://www.baidu.com/', 'BUG链接')
def test_with_named_issue():
pass
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
无name参数
有name参数
9、@allure.testcase()
链接(测试用例链接)
装饰器源码:
调用link(),但link_type=LinkType.TEST_CASE。
参数:
- url:跳转的链接。
- name:显示在 allure 报告的名字,如果不传就是显示完整的链接。
类似的装饰器:
访问链接:@allure.link()
Bug链接:@allure.issue()
1、创建test_allure_testcase.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
@allure.testcase('https://www.baidu.com/')
def test_with_testcase():
pass
@allure.testcase('https://www.baidu.com/', '测试用例地址')
def test_with_named_testcase():
pass
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
无name参数
有name参数
10、@allure.epic()/feature()/story()
allure 标记装饰器(可显示在测试报告上):
@allure.epic:敏捷里面的概念,定义史诗,往下是 feature。
@allure.feature:功能点的描述,理解成模块,往下是 story。
@allure.story:故事,往下是 title。
示例一:
1、创建test_allure_epic_feature_story.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
def test_without_any_annotations_that_wont_be_executed():
pass
@allure.story('story1')
def test_with_story1():
pass
@allure.story('story2')
def test_with_story2():
pass
@allure.feature('feature3')
@allure.story('story3')
def test_with_feature3_story3():
pass
@allure.epic('epic4')
@allure.feature('feature4')
@allure.story('story4')
def test_with_epic4_feature4_story4():
pass
@allure.epic('epic5')
@allure.feature('feature5')
class TestCase:
@allure.story('story5_1')
def test_with_story5_1(self):
print("执行 test_with_story5_1")
@allure.story('story5_2')
def test_with_story5_2(self):
print("执行 test_with_story5_2")
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
首页FEATURES BY STORIES区域显示所设置的标记
Behaviors栏目下,带有标记的测试用例显示的标记层次顺序
示例二:命令行运行,指定运行某个标记(epic、feature、story)
命令行参数:
- --allure-epics
- --allure-features
- --allure-stories
1、创建test_allure_epic_feature_story2.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
import allure
import os
@pytest.fixture(scope="session")
def login_fixture():
print("===前置操作-登陆===")
@allure.step("步骤1")
def step1():
print("===操作步骤1===")
@allure.step("步骤2")
def step2():
print("===操作步骤2===")
@allure.step("步骤3")
def step3():
print("===操作步骤3===")
@allure.epic("总体描述1")
@allure.feature("测试模块1")
class TestCaseAll1:
@allure.testcase("https://www.baidu.com/", "测试用例")
@allure.issue("https://www.baidu.com/", "Bug链接")
@allure.title("用例标题")
@allure.story("story1")
@allure.severity("critical")
def test_case1(self, login_fixture):
print("===测试用例1===")
step1()
step2()
@allure.story("story2")
def test_case2(self, login_fixture):
print("===测试用例2===")
step1()
step3()
@allure.epic("总体描述2")
@allure.feature("测试模块2")
class TestCaseAll2:
@allure.story("story3")
def test_case3(self, login_fixture):
print("===测试用例3===")
step1()
@allure.story("story4")
def test_case4(self, login_fixture):
print("===测试用例4===")
step3()
if __name__ == '__main__':
pytest.main(['-s', '-q', '--alluredir', './allure'])
os.system('allure -c ./allure')
os.system('allure serve ./allure')
2、运行结果:
(1)运行全部:
执行完成后,自动打开浏览器加载测试报告
(2)命令行指定运行:
1)、只运行epic名为“总体描述1”的测试用例
代码语言:javascript复制pytest --alluredir ./allure --allure-epics=总体描述1
allure serve allure
运行结果:
2)、只运行feature名为“测试模块2”的测试用例
代码语言:javascript复制pytest --alluredir ./allure --allure-features=测试模块2
allure serve allure
运行结果:
3)、只运行story1、story3的测试用例(可以不用=号 空格也可以)
代码语言:javascript复制pytest --alluredir ./allure test_allure_epic_feature_story2.py --allure-stories story1,story3
allure serve allure
运行结果:
4)运行指定的feature story的测试用例(可以不用=号 空格也可以)
代码语言:javascript复制pytest --alluredir ./allure test_allure_epic_feature_story2.py --allure-features 测试模块2 --allure-stories story2
allure serve allure
运行结果:
11、@allure.severity()
用来标记用例级别。
Allure 提供的用例等级:
- BLOCKER = 'blocker' 阻塞缺陷(功能未实现,无法下一步)
- CRITICAL = 'critical' 严重缺陷(功能点缺失)
- NORMAL = 'normal' 一般缺陷(边界情况,格式错误)
- MINOR = 'minor' 次要缺陷(界面错误与UI需求不符)
- TRIVIAL = 'trivial 轻微缺陷(必须项无提示,或者提示不规范等)
一、示例:
1、创建test_allure_severity.py文件
脚本代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import allure
def test_with_no_severity():
pass
@allure.severity(allure.severity_level.BLOCKER)
def test_with_blocker_severity():
pass
@allure.severity(allure.severity_level.CRITICAL)
def test_with_critical_severity():
pass
@allure.severity(allure.severity_level.MINOR)
def test_with_minor_severity():
pass
@allure.severity(allure.severity_level.TRIVIAL)
def test_with_trivial_severity():
pass
@allure.severity(allure.severity_level.NORMAL)
def test_with_normal_severity():
pass
@allure.severity(allure.severity_level.NORMAL)
class TestClassWithNormalSeverity(object):
def test_inside_the_normal_severity_test_class(self):
"""
测试类优先级 normal
"""
print("测试类优先级 normal")
@allure.severity(allure.severity_level.CRITICAL)
def test_inside_the_normal_severity_test_class_with_overriding_critical_severity(self):
"""
测试类优先级 normal
测试用例优先级 critical
"""
print("测试类优先级 normal;测试用例优先级 critical")
@allure.severity("normal")
def test_case_1():
""" normal 级别测试用例 """
print("normal 级别测试用例")
@allure.severity("critical")
def test_case_2():
""" critical 级别测试用例 """
print("critical 级别测试用例")
@allure.severity("blocker")
def test_case_3():
""" blocker 级别测试用例 """
print("blocker 级别测试用例")
@allure.severity("minor")
def test_case_4():
""" minor 级别测试用例 """
print("minor 级别测试用例")
@allure.severity("trivial")
def test_case_5():
""" trivial 级别测试用例 """
print("trivial 级别测试用例")
def test_case_6():
""" 未标记 severity 的用例默认为 normal """
print("未标记 severity 的用例默认为 normal")
@allure.severity("normal")
def test_case_7():
""" normal 级别测试用例 """
assert (1 == 2)
@allure.severity("critical")
def test_case_8():
""" critical 级别测试用例 """
assert (1 == 2)
@allure.severity("blocker")
def test_case_9():
""" blocker 级别测试用例 """
assert (1 == 2)
2、输入命令运行:
代码语言:javascript复制pytest -n auto --alluredir=allure
allure serve allure
运行结果:
Severity字段标记用例级别
图表里统计用例优先级
二、命令行参数运行:
根据优先级选择需要运行的测试用例
参数:
--allure-severities
例如:只运行severity=blocker、critical的测试用例,命令行输入
写法一:
代码语言:javascript复制pytest test_allure_severity.py -sq --alluredir=allure --allure-severities=blocker,critical
写法二:
代码语言:javascript复制pytest test_allure_severity.py -sq --alluredir=allure --allure-severities blocker,critical
运行结果:
按照需要运行的用例级别,运行了7条测试用例。