简介
pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。
根据pytest的官方网站介绍,它具有如下特点:
(1)非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考
(2)能够支持简单的单元测试和复杂的功能测试
(3)支持参数化
(4)执行测试过程中可以将某些测试跳过,或者对某些预期失败的case标记成失败
(5)支持重复执行失败的case
(6)支持运行由nose, unittest编写的测试case
(7)pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等
(8)方便的和持续集成工具集成
安装
py -3 -m pip install pytest
或者
py -3 -m pip install -U pytest
验证安装成功
pytest --version
pytest用例编写规则
(1)测试文件以test_开头(以_test结尾也可以),注意:pytest 文件名.py不受此规则限制。
(2)测试类以Test开头,并且不能带有 init 方法
(3)测试函数以test_开头
(4)断言使用基本的assert即可
pytest执行方式
pytest 在当前目录下运行所有测试
# 执行pytest目录下所有test_开头(以_test结尾也可以)的py文件
# 子目录中以_test开头或结尾的py文件也会被执行
...\pytest>pytest
pytest test_mod.py 执行指定的测试文件
# 执行某个测试文件
...\pytest>pytest test_a.py
pytest somepath 在指定路径下运行所有测试
# 执行指定目录下所有test_开头(以_test结尾也可以)的py文件
...\pytest>pytest pytest_sub_path
pytest -k stringexpr 当测试文件、测试类名、测试方法中包含stringexpr关键字时,均可以被执行
# 测试文件、测试类名、测试方法中包含指定关键字,匹配成功时,均可以被执行
F:\LiFuChe\python_20_自动化\pytest>pytest -k fixture
================================ test session starts ================================
platform win32 -- Python 3.10.2, pytest-7.1.2, pluggy-1.0.0
rootdir: F:\LiFuChe\python_20_自动化\pytest
plugins: html-3.1.1, metadata-2.0.2, ordering-0.6, rerunfailures-10.2
collected 49 items / 29 deselected / 20 selected
test_fixture1.py . [ 5%]
test_fixture2.py ... [ 20%]
test_fixture3.py ... [ 35%]
test_fixture4.py ... [ 50%]
test_fixture5.py .F [ 60%]
test_fixture6.py .... [ 80%]
conftest\test_fixture_module.py FF [ 90%]
test_conftest\test_fixture_module.py FF
pytest test_mod.py::test_func 仅运行与节点ID匹配的测试
pytest test_a.py::test_case1 #执行test_a.py文件下的test_case1函数
pytest test_mod.py::TestClass::test_method #执行指定测试类TestClass中的test_method 方法
pytest常用命令
使用pytest --help可以查看全部选项
命令****说明-q等价于pytest --quiet,简化输出信息-s等价于pytest --capture=no,输出测试用例中的打印信息-v等价于pytest --verbose,显示具体的详情信息(哪个测试用例的哪个测试方法被执行),一般显示错误的位置及错误的详细信息-m用于标记测试并分组,以便快速选中并运行。需要先在待分组的方法前加上@pytest.mark.mark_name这样的装饰器,执行时用pytest-m mark_name。
-m还可以用表达式指定多个标记。使用-m "mark1 and mark2"可以同时选中带有这两个标记的所有测试用例。使用-m "mark1 and not mark2"则会选中带有mark1但不带mark2的测试用例;使用-m "mark1 or mark2"则选中带有mark1或mark2的所有测试用例-k后面可为测试文件、测试类名、测试方法中包含的关键字,匹配成功时,均可以被执行--lf等价于--last-failed,只重新运行上次运行失败的用例(如果没有失败的话,会全部跑)--ff等价于--failed-first,运行所有测试用例,但首先运行上次运行失败的测试--x等价于--exitfirst,遇到错误或者用力不通过,则退出执行--maxfailed=num指定执行失败次数后停止
pytest测试报告
生成测试报告需要安装插件:
py -3 -m pip install pytest-html
或:pip install -U pytest-html
执行用例的命令:
pytest --html=report.html
失败重跑
需要安装插件:
py -3 -m pip install pytest-rerunfailures
或:pip install -U pytest-rerunfailures
运行命令:
pytest test_sample2.py --reruns n
n表示重试的次数
setup和teardown函数
setup和teardown:每个测试函数运行时,运行一次
import pytest
class Test_ST():
def setup(self):
print("------setup------")
def teardown(self):
print("------teardown------")
def test_001(self):
assert True
def test_002(self):
assert False
setup_class和teardown_class:一个测试类只运行一次
import pytest
class Test_ST():
def setup_class(cls):
print("------setup_class------")
def teardown_class(cls):
print("------teardown_class------")
def test_001(self):
assert True
def test_002(self):
assert True
控制测试函数的运行顺序
需要安装插件:
py -3 -m pip install pytest-ordering
使用访求:
- 使用 @pytest.mark.run(order=x) 标记被测试函数;
- 运行的顺序由order传入的参数决定;(order从小到大的顺序执行)
import pytest
class Test_ST():
@pytest.mark.run(order=3)
def test_001(self):
print("001...")
assert True
@pytest.mark.run(order=2)
def test_002(self):
print("002...")
assert True
@pytest.mark.run(order=1)
def test_003(self):
print("003...")
assert True
pytest.ini:通过配置文件配置要执行的测试用例
(1)pytest的配置文件存放位置及命名:
通常放在测试目录下,名称为pytest.ini,命令行运行时会使用配置文件中的配置
(2)配置pytest命令行运行参数
[pytest]
addopts=-s ... # 以空格分隔,可添加个命令行参数;所以参数均为插件包的参数
名称固定不要乱改
(3)配置测试搜索的路径
[pytest]
testpaths=./scripts # 表示当前目录下的scripts目录,srcipts目录可自定义
(4)配置测试搜索的文件名
[pytest]
python_files=test_*.py # 表示当前目录下的scripts目录下,以test_开头,.py结尾的所有文件,文件名可自定义
(5)配置测试的测试类名
[pytest]
python_classes=Test_* #当前目录下的scripts目录下,以test_开头,以.py结尾的所有文件中,以Test_开头的类,类可自定义
(6)配置测试的测试函数名
[pytest]
python_functions=test_* #当前目录下的scripts目录下,以test_开头,以.py结尾的所有文件中,以Test_开头的类内,以test_开头的方法,方法可自定义
目录结构:
pytest.ini
[pytest]
addopts = -s --html=./report/test_report.html
testpaths = ./scripts
python_files = test_*.py
python_classes = Test_*
python_functions = test_*
t1.py
def test_t1():
print("test_t1")
assert True
test_t1.py
import pytest
def test_1():
print("test_1")
assert True
test_t2.py
import pytest
class Test_2():
def test_2_1(self):
assert True
def test_2_2(self):
assert True
def t_2_3(self):
assert True
@pytest.fixture
pytest中加入fixture装饰器来标记固定的工厂函数,使测试能够可靠、重复地执行,fixture函数可以在测试执行前和执行后进行必要的准备和清理工作,和unitest测试框架中的setup、teardown类似,但是pytest fixture和传统xUnit风格的setup/teardown函数相比,有了巨大的改进:
(1)fixture具有明确的名称,并通过在测试函数、模块、类或整个项目中声明它们的使用来激活。
(2)fixture是以模块化的方式实现的,因为每个fixture名称都会触发fixture函数,其本身也可以使用其他fixture。
(3)fixture管理从简单的单元扩展到复杂的函数测试,允许根据配置和组件选项参数化fixture和测试,或者在函数、类、模块或整个测试会话范围内重复使用fixture。
方法和参数
@pytest.fixture(scope=”function”,params=None,autouse=False,ids=None,name=None)
常用参数:
scope:被标记方法的作用域
- “function” (default):作用于每个测试方法,每个test都运行一次
- “class”:作用于整个类,每个class的所有test只运行一次
- “module”:作用于整个模块,每个module的所有test只运行一次
- “session”:作用于整个session,每个session只运行一次 【慎用】
params:(list类型)提供参数数据,供调用标记方法的函数使用
autouse:是否自动执行,默认为False不运行,设置为True自动运行
ids:每个字符串id的列表,每个字符串对应于params,这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成
name:fixture的名称。默认为装饰函数的名称。(一般不用)
如果fixture在定义它的统一模块中使用,fixture的功能名称将被请求fixture的功能arg遮蔽,解决这个问题的一种方法是将装饰函数命令"fixture_<fixturename>"然后使用"@pytest.fixture(name='<fixturename>')"
作为参数引用
直接将pytest.fixture函数的执行结果,作为参数传递给被测试函数
import requests
import pytest
@pytest.fixture
def baidu_response():
print("执行fixture")
return requests.get("http://www.baidu.com")
def test_baidu(baidu_response):
response = baidu_response
assert response.status_code == 200
作为函数引用
import pytest
# fixture作为函数引用
@pytest.fixture()
def before():
print("before执行啦。。。")
@pytest.mark.usefixtures("before") # 每个测试方法执行前执行,不包括setup、teardown
class Test_before():
def setup(self):
print("setup。。。")
def test_a(self):
print("test_a。。。")
def test_b(self):
print("test_b。。。")
@pytest.mark.usefixtures("before") # 函数执行前执行
def test_c():
print("test_c。。。")
设置自动执行
import pytest
# fixture作为函数引用
@pytest.fixture(autouse=True)
def before():
print("before执行啦。。。")
class Test_before():
def setup(self):
print("setup。。。")
def test_a(self):
print("test_a。。。")
def test_b(self):
print("test_b。。。")
def test_c():
print("test_c。。。")
设置作用域
test_fixture4.py
import pytest
@pytest.fixture(scope="function",autouse=True) # 如果不设置自动运行将不会被调用
def before():
print("bofore执行啦。。。")
class Test_before():
def setup(self):
print("setup。。。")
def test_a(self):
print("test_a。。。")
def test_b(self):
print("test_b。。。")
def test_c():
print("test_c。。。")
作用域为function
每个函数、类中的每个方法都运行一次
作用域为class
一个类只运行一次
作用域为module
一个模块运行一次
作用域为session
不建议使用,影响范围大
返回值
import pytest
@pytest.fixture
def generator_num():
return 1
def test_1_generator_num(generator_num):
assert generator_num==1
def test_2_generator_num(generator_num):
assert generator_num==2
参数化
import pytest
@pytest.fixture(params=[1,2,3])
def init_xx(request): # 参数为固定用法
return request.param # 取出单个参数,也为固定用法
class Test_xx:
def setup_class(self):
print("setup_class------")
def teardown_class(self):
print("teardown_class------")
def test_xx(self,init_xx): # 每个参数执行一遍
print("test_xx------")
assert init_xx !=4
def test_yy(self): # 只执行一次
print("test_yy------")
assert True
@pytest.mark
skipif跳过测试函数
使用方法:
@pytest.mark.skipif(condition,reason=None)
参数:
- condition:跳过的条件,True(跳过、不执行)/False(不跳过、执行),必传参数
- reason:标注原因
import pytest
class Test_skip:
def test_a(self):
assert True
@pytest.mark.skipif(2>1,reason="故意的") #条件为boolean值,True(跳过)/False(执行)
def test_b(self):
assert False
import pytest
def is_res():
# return False
return True
class Test_skip:
def test_a(self):
assert True
@pytest.mark.skipif(is_res(),reason="故意的") # 条件为boolean值,True(跳过)/False(不跳过/执行)
def test_b(self):
assert True
xfail预期失败函数
标记测试函数为失败函数
@pytest.mark.xfail(condition,reason=None)
参数:
- condition:失败的条件,True(失败),必传参数
- reason:标注原因
import pytest
class Test_xfail:
def test_a(self):
assert True
@pytest.mark.xfail(True,reason="故意的") # 条件为boolean值,True(跳过)/False(不跳过/执行)
def test_b(self):
assert True
parametrize参数化函数
@pytest.mark.parametrize(argnames,argvalues,indirect=False,ids=None,scope=None)
常用参数:
- argnames:参数名称
- argvalues:参数对应的值,类型必须为list
注意:与fixture的参数化使用方式不同,比fixture更灵活、方便
单个参数
import pytest
class Test_para:
@pytest.mark.parametrize('name', ["tom", "lisa", "lucy"])
def test_p1(self, name): # 要传参数的名称,且和参数化中定义的一致
print("name:",name)
assert name != "haha"
多个参数
import pytest
def login_data():
data=[('wang','wang123'),('li','li23'),('zhao','zhao123')]
return data
class Test_param:
@pytest.mark.parametrize("username,password",login_data())
def test_login(self,username,password):
print("用户名:%s,密码:%s 登录成功!"%(username,password))
assert True
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time
@pytest.mark.parametrize(
"num,search_key",
[("3","光荣之路"),
("2","Selenium"),
("1","python"),
],
ids=["case1","case2","case3"]
# ids中的数据相当于用例名称,如果不写,报告中的用例名称会有中文乱码问题
)
def test_baidu_search(num,search_key):
s = Service("chromedriver.exe")
# driver = webdriver.Chrome(executable_path="chromeDriver")
driver = webdriver.Chrome(service=s)
driver.get("https://www.baidu.com")
time.sleep(2)
driver.find_element(By.ID, "kw").send_keys(search_key)
driver.find_element(By.ID, "su").click()
time.sleep(2)
assert driver.title==search_key+"_百度搜索"
driver.quit()
运行命令:pytest test_parametrize3.py -v --html=parametrize3_report.html
conftest.py 在指定范围内共享fixture实例
将fixture函数放入单独的conftest.py文件中,以便目录中多个测试模块的测试可以访问fixture函数,使用时不需要导入,Pytest会自动发现它。fixture函数的发现规则从测试类开始,然后是测试模块,然后是conftest.py文件,最后是内置插件和第三方插件。
范围:在类、模块或会话中跨测试共享一个fixture实例
使用conftest.py的规则:
(1)conftest.py这个文件名是固定的,不可以更改。
(2)conftest.py与运行用例在同一个包下,并且该包中有__init__.py文件
(3)使用的时候不需要导入conftest.py,会自动寻找。
conftest.py文件的作用域是当前包内(包括子包);如果函数被调用,会优先从当前测试类中寻找,然后是模块(.py文件)中,接着是当前包中寻找(conftest.py中),如果没有再找父包直至根目录;如果我们要声明全局的conftest.py文件,我们可以将其放在根目录下
fixture的作用范围:
fixture里面有个scope参数可以控制fixture的作用范围:session>module>class>function
-function:每一个函数或方法都会调用
-class:每一个类调用一次,一个类中可以有多个方法
-module:每一个.py文件调用一次,该文件内又有多个function和class
-session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module
test_fixture_scope.py
def test_ehlo(smtp):
"""执行结果:失败"""
response, msg = smtp.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
assert 0
def test_noop(smtp):
"""执行结果:失败"""
response, msg = smtp.noop()
assert response == 250
assert 0
scope="function"
conftest.py
import pytest
import smtplib
@pytest.fixture(scope="function")
def smtp():
return smtplib.SMTP("smtp.qq.com", 587, timeout=5)
运行命令:pytest test_fixture_scope.py
当scope="function"时,每个测试函数都调用一次smtp(),所以可看到两个测试函数使用的smtp对象不同
scope="module"
import pytest
import smtplib
@pytest.fixture(scope="module")
def smtp():
return smtplib.SMTP("smtp.qq.com", 587, timeout=5)
运行命令:pytest test_fixture_scope.py
可以看到同一模块范围内的smtp对象被传递到两个测试函数中,因为pytest显示了回溯中的传入参数值。因此,使用smtp的两个测试函数的运行速度与单个测试函数差不多,因为它们重用了相同的实例。
先实例化更大范围的设备
在特性的函数请求中,高范围(如会话)的fixture比低范围fixture(如函数或类)先被实例化。相同范围内的固定装置的相对顺序遵循测试功能中声明的顺序,并尊重固定装置之间的依赖关系。
import pytest
@pytest.fixture(scope="session")
def s1():
print("s1...session....")
@pytest.fixture(scope="module")
def m1():
print("m1...module...")
@pytest.fixture
def f1():
print("f1...function...")
@pytest.fixture
def f2():
print("f2...function...")
def test_foo(f1, m1, f2, s1):
f1=f1
m1=m1
f2=f2
s1=s1
assert 0
fixture的完成与拆卸(teardown)代码
1) yield方式
当fixture超出范围时,pytest支持执行fixture特定的最终代码,通过使用yield语句而不是return,yield语句之后的所有代码都用作拆卸代码。
conftest.py
import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp():
smtp = smtplib.SMTP("smtp.qq.com", 587, timeout=5)
yield smtp
print("teardown smtp...")
smtp.close()
print和smtp.close()语句将在模块的最后一次测试完成后执行,不管测试的异常状态如何
注意:如果我们用scope='function'修饰fixture函数,那么每个测试都会发生fixture设置和清理。
test_fixture_teardown.py
def test_ehlo(smtp):
"""执行结果:失败"""
response, msg = smtp.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
assert 0
def test_noop(smtp):
"""执行结果:失败"""
response, msg = smtp.noop()
assert response == 250
assert 1
2) addfinalizer方式(推荐使用)
conftest.py
import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp(request):
smtp = smtplib.SMTP("smtp.qq.com", 587, timeout=5)
def fin():
print("teardown smtp...")
smtp.close()
request.addfinalizer(fin)
return smtp
yield和addfinalizer方式的区别:
yield和addfinalizer方法在测试结束后调用其代码的工作方式相似,但addfinalizer与yield有两个关键区别:
(1)addfinalizer 可以注册多个终结器函数。
(2)addfinalizer 无论fixture设置代码是否引发异常,都将始终调用终结器。即使其中一个无法创建/获取,也可以方便地正确关闭设备创建的所有资源
fixture参数化
conftest.py
import pytest
@pytest.fixture(scope="module",params=["smtp.gmail.com", "smtp.qq.com"])
def func_param(request):
return request.param # 通过request.param访问参数的值
test_fixture_params1.py
def test_func_param_1(func_param):
"""执行结果:失败"""
res=func_param
print(res+"111111111")
assert 0
def test_func_param_2(func_param):
"""执行结果:失败"""
res=func_param
print(res+"222222222")
assert 0
以上可以看出两个测试函数每个都运行了两次,而且是针对不同的参数。
pytest将建立一个字符串,它是参数化fixture中每个fixture值的测试ID,在上例中,test_func_param_1[smtp.qq.com]和test_func_param_1[smtp.qq.com],这些ID可以与-k一起使用来选择要运行的特定实例,还可以在发生故障时识别特定实例。
使用--collect-only运行pytest会显示生成的ID
如:
运行命令:pytest test_fixture_params1.py --collect-only
fixture作用域
文件夹级别的覆盖
目录结构:
fixture_workspace_1/conftest.py
import pytest
@pytest.fixture
def username():
return 'Parmley'
fixture_workspace_1/test_a.py
def test_username(username):
assert username == 'Parmley'
fixture_workspace_1/sub/conftest.py
import pytest
@pytest.fixture
def sub_username(username):
return 'sub-' + username
fixture_workspace_1/sub/test_a.py
def test_username(sub_username):
assert sub_username == 'sub-Parmley'
说明:fixture_workspace_1/conftest.py中的username作为参数引用传递给了fixture_workspace_1/sub/conftest.py里的sub_username方法
模块级别的覆盖
目录结构:
fixture_workspace_2/conftest.py
import pytest
@pytest.fixture
def username():
return 'Parmley'
fixture_workspace_2/test_a.py
import pytest
@pytest.fixture
def username(username):
return 'ta-' + username
def test_username(username):
print(username)
assert username == 'ta-Parmley'
fixture_workspace_2/test_b.py
import pytest
@pytest.fixture
def username(username):
return 'tb-' + username
def test_username(username):
print(username)
assert username == 'tb-Parmley'
说明:fixture_workspace_2/conftest.py中的username作为参数引用传递给了fixture_workspace_1/test_a.py和test_b.py里的username方法
参数化覆盖
fixture_workspace_3/conftest.py
import pytest
@pytest.fixture
def username():
return 'Parmley'
@pytest.fixture
def other_username(username):
return 'other-' + username
fixture_workspace_3/test_a.py
import pytest
@pytest.mark.parametrize('username', ['directly-overridden-username-ta'])
def test_username(username):
print(username)
assert username == 'directly-overridden-username-ta'
fixture_workspace_3/test_b.py
import pytest
@pytest.mark.parametrize('username', ['directly-overridden-username-tb'])
def test_username(username):
print(username)
assert username == 'directly-overridden-username-tb'
说明:conftest不会影响到被@parametrize装饰的函数的同名参数值
Allure
Allure是一个独立的报告插件,生成美观易读的报告,支持的语言:java,python,php,ruby等。
下载Allure
选择点击进入:(我选择的是2.19.0版本)
下载zip包,并直接解压到某路径下,如解压到D盘,进入bin目录,双击allure.bat
在环境变量path中添加allure的bin目录,如E:\Programs\allure-2.19.0\bin
在cmd中,输入allure --version,验证是否安装成功
allure --version
安装pytest-allure
pip3 install pytest-allure-adaptor
或pip3 install allure-pytest
生成报告
pytest [测试文件] --alluredir=./result #--alluredir用于指定存储测试结果的路径
【注意事项】
如果运行报错,可能是pytest版本太高,换个低版本的就可以了:
pip3 uninstall pytest
pip3 install pytest==4.0.2
查看测试报告
方式一:直接打开默认浏览器展示报告
在cmd窗口对应路径下,运行如下命令:
allure serve ./result/
方式二:从结果生成报告
生成报告
allure generate ./result/ -o ./report/ --clean (覆盖路径加–clean)
打开报告
allure open -h 127.0.0.1 -p 8883 ./report/
allure特性
参考文章:Pytest测试框架(五):pytest + allure生成测试报告
添加feature、story、step
可以在报告中添加用例描述信息,比如测试功能,子功能或场景,测试步骤以及测试附加信息:
- @allure.feature(‘功能名称’):相当于 testsuite
- @allure.story(’子功能名称‘):对应这个功能或者模块下的不同场景,相当于 testcase
- @allure.step(‘步骤’):测试过程中的每个步骤,放在具体逻辑方法中 - @allure.step(‘步骤’) 只能以装饰器的形式放在类或者方法上面- with allure.step:可以放在测试用例方法里面
- @allure.attach(‘具体文本信息’):附加信息:数据,文本,图片,视频,网页
import pytest
import allure
@allure.feature("登录")
class TestLogin():
@allure.story("登录成功")
def test_login_success(self):
print("登录成功")
pass
@allure.story("密码错误")
def test_login_failure(self):
with allure.step("输入用户名"):
print("输入用户名")
with allure.step("输入密码"):
print("输入密码")
print("点击登录")
with allure.step("登录失败"):
assert '1' == 1
print("登录失败")
pass
@allure.story("用户名密码错误")
def test_login_failure_a(self):
print("用户名或者密码错误,登录失败")
pass
@allure.feature("注册")
class TestRegister():
@allure.story("注册成功")
def test_register_success(self):
print("测试用例:注册成功")
pass
@allure.story("注册失败")
@allure.step(title="自己写的测试步骤1...2")
def test_register_failure(self):
with allure.step("输入用户名"):
print("输入用户名")
with allure.step("输入密码"):
print("输入密码")
with allure.step("再次输入密码"):
print("再次输入密码")
print("点击注册")
with allure.step("注册失败"):
assert 1 + 1 == 2
print("注册失败")
pass
用例执行、生成报告
pytest test_allure_step.py --alluredir=./result/2
allure generate ./result/2 -o ./report/2/ --clean
allure open -h 127.0.0.1 -p 8883 ./report/2
添加allure.attach
可以在报告中附加文本、图片以及html网页,用来补充测试步骤或测试结果,比如错误截图或者关键步骤的截图。
import allure
import pytest
def test_attach_text():
allure.attach("纯文本", attachment_type=allure.attachment_type.TEXT)
def test_attach_html():
allure.attach("<body>这是一段htmlbody块</body>", "html页面", attachment_type=allure.attachment_type.HTML)
def test_attach_photo():
allure.attach.file("test.jpg", name="图片", attachment_type=allure.attachment_type.JPG)
用例执行:
pytest test_allure_attach.py --alluredir=./result/5
allure serve ./result/5
添加link, issue, testcase
可以在测试报告中添加链接、bug地址、测试用例地址。
关联bug可在用例执行时添加参数:
- –allure-link-pattern=issue:[bug地址]{}
- 例如:–allure-link-pattern=issue:http://www.bugfree.com/issue/{}
import allure
@allure.link("http://www.baidu.com", name="baidu link")
def test_with_link():
pass
@allure.issue("http://www.baidu.com/test_02","this is a issue")
def test_with_issue_link():
pass
TEST_CASE_LINK = 'http://www.baidu.com/test_03'
@allure.testcase(TEST_CASE_LINK, 'Test case title')
def test_with_testcase_link():
pass
用例执行、报告查看
#执行用例并保存结果
pytest test_allure_link_issue.py --alluredir=./result/3
#或使用如下方式
pytest test_allure_link_issue.py --allure-link-pattern=issue:http://www.bugfree.com/issue/{} --alluredir=./result/3
#查看测试报告
allure serve ./result/3
点击链接会跳转到指定页面
添加severity
allure.severity按重要性级别来标记,有5种级别:
- Blocker:阻塞
- Critical:严重
- Normal:正常(默认值)
- Minor:不太重要
- Trivial:不重要
import allure
import pytest
def test_with_no_severity_label():
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.BLOCKER)
def test_with_blocker_severity():
pass
@allure.severity(allure.severity_level.NORMAL)
class TestclassWithNormalSeverity(object):
def test_inside_the_normal_severity_test_no_severity(self):
pass
@allure.severity(allure.severity_level.CRITICAL)
def test_inside_the_normal_severity_test_critical_severity(self):
pass
用例执行
pytest test_allure_severity.py --alluredir=./result/4 --allure-severities normal,critical
allure serve ./result/4
版权归原作者 黎扶澈 所有, 如有侵权,请联系我们删除。