pytest测试框架总结
pytest测试框架
特点:
1、非常容易上手,入门简单,文档丰富,文档中有很多参考实例
2、支持简单的单元测试和复杂的功能测试
3、支持参数化
4、执行测试用例过程中,支持跳过操作
5、支持重复执行失败的case
6、支持运行由Nose,unittest编写的测试case
7、pytest支持很多第三方插件
8、方便的和持续集成工具集成
1、pytest介绍及安装
-
pytest安装(3种方式)
-
在线安装 pip install pytest
-
离线安装方式 下载pytest离线安装包,并解压,然后在DOS下进入到解压的目录,然后执行
python setup.py install
-
pycharm
-
-
判断是否安装成功:
- pip show pytest
- pycharm
2、pytest类定义及方法定义及运行
-
pytest测试类的定义:类名必须是以Test开头
-
pytest测试方法的定义:方法名必须是以test开头
-
执行:
- 在pycharm中右击方法名或者类名可以直接执行对应测试类或者测试方法
- 在pycharm中右击方法名或者类名可以直接执行对应测试类或者测试方法
-
第二种运行方式: 通过pytest -s -v 测试文件名称 (-s 输出的用例输出的信息, -v输出的是执行的用例的类名以及方法名)
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
# 定义一个pytest方法
def test_add_001(self):
result = add(5, 8)
print(result)
def test_add_002(self):
result = add(105, 9)
print(result)
--D:\PycharmProjects\UItest\test_t>pytest -s -v test_001.py
3、pytest断言
-
pytest里面的断言方法就只有一个
assert 表达式
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
# 定义一个pytest方法
def test_add_001(self):
result = add(1, 2)
print(result)
assert result == 3 #判断相等
assert result != 4 #判断不想等
assert result #判断为Ture
#assert False #判断为False
#assert "a" in "abc" #判断包含
#assert "a" not in "abc" # 判断不包含
#assert result is None # 判断是否为空
assert result is not None # 判断是否不为空
4、pytest方法级别的fixture
- pytest方法级别的fixture是针对每个测试方法,在执行测试方法前会执行fixture初始化的操作,在执行完测试方法后,执行fixture销毁的操作
- 初始化的操作方法: def setup(self): 方法来实现。----setup要小写
- 销毁的操作方法: def teardown(self): 方法来实现。-----teardown要小写
import time
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
def setup(self):
print("测试用例开始执行时间",time.strftime("%Y-%m-%D-%M-%S"))
# 定义一个pytest方法
def test_add_001(self):
result = add(1, 2)
print(result)
def test_add_002(self):
result = add(2, 2)
print(result)
def teardown(self):
print("测试用例结束时间", time.strftime("%Y-%m-%D-%M-%S"))
======================== 2 passed, 1 warning in 0.04s =========================
Process finished with exit code 0
测试用例开始执行时间 2022-07-09 19:29:34
PASSED [ 50%]3
测试用例结束时间 2022-07-09 19:29:34
测试用例开始执行时间 2022-07-09 19:29:34
PASSED [100%]4
测试用例结束时间 2022-07-09 19:29:34
5、pytest类级别的fixture
fixture同通常用来对测试方法,测试函数,测试类和整个测试文件进行初始化或还原测试环境。
-
pytest 类级别的fifixture针对每个测试类的初始化和销毁的操作,可以放在以下两个方法中
-
类级别初始化的方法: def setup_class(self):
-
类级别销毁的方法: def teardown_class(slef):
方法名称固定,不能修改。
-
fixture的方法必须写在测试类当中,不能写在测试类外面。
import time
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
#添加类级别的初始化操作方法
def setup_class(self):
print("类开始执行时间", time.strftime("%Y-%m-%d %H:%M:%S"))
#添加类级别的销毁操作方法
def teardown_class(self):
print("类结束执行时间", time.strftime("%Y-%m-%d %H:%M:%S"))
def setup(self):
print("测试用例开始执行时间",time.strftime("%Y-%m-%d %H:%M:%S"))
# 定义一个pytest方法
def test_add_001(self):
result = add(1, 2)
print(result)
def test_add_002(self):
result = add(2, 2)
print(result)
def teardown(self):
print("测试用例结束时间", time.strftime("%Y-%m-%d %H:%M:%S"))
================================== 2 passed in 0.03s==================================
collected 2 items
test_add_01.py::Test_add::test_add_001
类开始执行时间 2022-07-09 20:02:27
测试用例开始执行时间 2022-07-09 20:02:27
3
PASSED测试用例结束时间 2022-07-09 20:02:27
test_add_01.py::Test_add::test_add_002
测试用例开始执行时间 2022-07-09 20:02:27
4
PASSED测试用例结束时间 2022-07-09 20:02:27
类结束执行时间 2022-07-09 20:02:27
6:前置方法,后置方法
前置方法:
- setup_function ---只对普通的方法有效,def test_XXX()
- setup_method ----只对类内部的方法有效,class TestXXX ---def test_XXX(self)
- setup_class ------只对类有效 并且要放在类内部
- setup_module ----对py文件有效
- 当脚本里有普通方法,有类方法混合时,都想用初始化,就用model,在当下的py脚本都是有效的
后置方法:
- teardown_function
- teardown_method
- teardown_class
- teardown_module
举例:
实验1:setup_function方法
- -----只对普通的方法有效,def test_XXX()
def setup_function():
print("setup_function():每个方法之前执行")
def teardown_function():
print("teardown_function():每个方法之后执行")
def test_01():
print("正在执行test1")
def test_02():
print("正在执行test2")
data_test.py::test_01
setup_function():每个方法之前执行
正在执行test1
PASSEDteardown_function():每个方法之后执行
data_test.py::test_02
setup_function():每个方法之前执行
正在执行test2
PASSEDteardown_function():每个方法之后执行
-
如果.py文件中既有类又有方法,使用setup_function会是怎样的效果?
---只对普通的方法有效 对类中的方法无效
def setup_function():
print("setup_function():每个方法之前执行")
def test_01():
print("正在执行test1")
def test_02():
print("正在执行test2")
def teardown_function():
print("teardown_function():每个方法之后执行")
class Test_pytest():
def test_03(self):
print("类中的方法test3")
data_test.py::test_01
setup_function():每个方法之前执行
正在执行test1
PASSED
teardown_function():每个方法之后执行
data_test.py::test_02
setup_function():每个方法之前执行
正在执行test2
PASSED
teardown_function():每个方法之后执行
data_test.py::Test_pytest::test_03
类中的方法test3
PASSED
实验2:setup_method方法
- ----只对类内部的方法有效,class TestXXX ---def test_XXX(self)
class Test_setup():
def setup_method(self):
print("初始化方法")
def test_01(self):
print("测试方法1")
def test_02(self):
print("测试方法2")
def teardown_method(self):
print("结束方法")
data_test.py::Test_setup::test_01
初始化方法
测试方法1
PASSED结束方法
data_test.py::Test_setup::test_02
初始化方法
测试方法2
PASSED结束方法
实验3:setup_class方法
- ----只对类有效 并且要放在类内部
class Test_setup():
def setup_class(self):
print("初始化方法")
def test_01(self):
print("测试方法1")
def test_02(self):
print("测试方法2")
def teardown_class(self):
print("结束方法")
data_test.py::Test_setup::test_01
初始化方法
测试方法1
PASSED
data_test.py::Test_setup::test_02
测试方法2
PASSED
结束方法
实验4:setup_module方法
- 当脚本里有普通方法,有类方法混合时,都想用初始化,就用module,在当下的py脚本都是有效的
def setup_module():
print("setup_function():每个方法之前执行")
def test_01():
print("正在执行test1")
def test_02():
print("正在执行test2")
def teardown_module():
print("teardown_function():每个方法之后执行")
class Test_pytest():
def test_03(self):
print("类中的方法test3")
data_test.py::test_01 setup_function():
每个方法之前执行
正在执行test1
PASSED
data_test.py::test_02
正在执行test2
PASSED
data_test.py::Test_pytest::test_03
类中的方法test3
PASSEDteardown_function():
每个方法之后执行
8、pytest配置文件
pytest的配置文件有固定的三个名称: pytest.ini tox.ini setup.cfg 这三个配置文件是放在项目的根目录下。
[pytest] # 标识当前配置文件是pytest的配置文件
addopts = -s -v # 标识pytest执行时增加的参数
testpaths = ./scripts # 匹配搜索的目录
python_files = test_*.py # 匹配测试文件
python_classes = Test* # 匹配测试类
python_functions = test_* # 匹配测试方法
一、Pytest常用插件
1、pytest测试报告
-
安装pytest测试报告插件
- 在线安装 pip install pytest-html
- 离线安装
- pycharm
-
使用方法
addopts = -s -v --html=report/report.html
2、控制用例执行顺序
-
unittest测试用例执行顺序是根据测试方法名称的assicc码值的大小来的,值越小排在前面(a-z)
-
pytest 正常情况下是根据测试方法的从上到下的顺序来执行.
- 可以通过 pytest-ordering 插件来控制pytest测试方法执行的顺序。
-
安装:
- 在线安装: pip install pytest-ordering
- 离线安装: 下载对应的离线安装包,解压后,并进入到对应的目录,执行 python setup.py install
- pycharm
-
使用
@pytest.mark.run(order=x) # x 表示的是整数,(既可以是负数也可以是正数)
- 全为负数或者正数时,值越小,优先级越高
- 既有正数,又有负数,那么正数优先级高 (2 -3 -1)
- 没有确定执行顺序的用例优先于负数
@pytest.mark.last # 设置用例最后执行
示例: 编写一个测试类,不用pytest-ordering,观察方法的执行顺序
示例2:方法名上面加上 @pytest.mark.run(order=x) 观察方法执行顺序
import time
import pytest
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
# 定义一个pytest方法
@pytest.mark.run(order=5)
def test_add_001(self):
result = add(1, 2)
print(result)
assert result==3
@pytest.mark.run(order=4)
def test_add_002(self):
result = add(2, 2)
print(result)
assert result==4
@pytest.mark.run(order=3)
def test_add_003(self):
result = add(3, 2)
print(result)
assert result==5
============================= 3 passed in 0.05s =================================
collected 3 items
scripts/test_ordering.py::Test_add::test_add_003 5
PASSED
scripts/test_ordering.py::Test_add::test_add_002 4
PASSED
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED
3、失败重试
-
安装:
- 在线安装: pip install pytest-rerunfailures
- 离线安装: 下载对应的离线安装包,解压后,并进入到对应的目录,执行 python setup.py install
- pycharm
-
使用:
在addopts参数行中增加对应的参数项: --reruns 2
当重复执行成功时,就不会再重复执行。
示例:将test_add_003断言改为失败 ini文件中addopts参数设置 --reruns 2 -
import time
import pytest
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
# 定义一个pytest方法
@pytest.mark.run(order=5)
def test_add_001(self):
result = add(1, 2)
print(result)
assert result==3
@pytest.mark.run(order=4)
def test_add_002(self):
result = add(2, 2)
print(result)
assert result==4
@pytest.mark.run(order=3)
def test_add_003(self):
result = add(3, 2)
print(result)
assert result==4
collected 3 items
scripts/test_ordering.py::Test_add::test_add_003 5
RERUN
scripts/test_ordering.py::Test_add::test_add_003 5
RERUN
scripts/test_ordering.py::Test_add::test_add_003 5
FAILED
scripts/test_ordering.py::Test_add::test_add_002 4
PASSED
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED
=================== short test summary info =============================================
FAILED scripts/test_ordering.py::Test_add::test_add_003 - assert 5 == 4
================== 1 failed, 2 passed, 2 rerun in 0.12s =================================
二、 pytest高级用法
1、跳过
1.1直接跳过
@pytest.mark.skip(reason=None)
- reason表示的是跳过的原因
1.2满足条件跳过
@pytest.mark.skipif(condition, reason=None)
- condition 表示是跳过的条件
可以在测试类和测试方法上使用
- 示例1:在测试类使用直接跳过-----@pytest.mark.skip("版本已更新,不需要在进行测试")
import time
import pytest
def add(a, b):
return a + b
# 定义一个pytest类
@pytest.mark.skip("版本已更新,不需要在进行测试")
class Test_add:
# 定义一个pytest方法
def test_add_001(self):
result = add(1, 2)
print(result)
assert result==3
def test_add_002(self):
result = add(2, 2)
print(result)
assert result==4
def test_add_003(self):
result = add(3, 2)
print(result)
assert result==5
collected 3 items
scripts/test_ordering.py::Test_add::test_add_001 SKIPPED (版本已更新,不需要在进行测试)
scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (版本已更新,不需要在进行测试)
scripts/test_ordering.py::Test_add::test_add_003 SKIPPED (版本已更新,不需要在进行测试)
============================== 3 skipped in 0.06s ======================================
- 示例1:在测试方法使用直接跳过-----@pytest.mark.skip("版本已更新,不需要在进行测试")
import time
import pytest
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
# 定义一个pytest方法
def test_add_001(self):
result = add(1, 2)
print(result)
assert result==3
@pytest.mark.skip("版本已更新,不需要在进行测试")
def test_add_002(self):
result = add(2, 2)
print(result)
assert result==4
def test_add_003(self):
result = add(3, 2)
print(result)
assert result==5
collected 3 items
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED
scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (版本已更新,不需要在进行测试)
scripts/test_ordering.py::Test_add::test_add_003 5
PASSED
============================== 2 passed, 1 skipped in 0.05s =============================
-
示例3:测试类使用-------满足条件跳过
version = 21 @pytest.mark.skipif(version>20,reason="大于2.0版本不需要在执行次用例")
import time import pytest def add(a, b): return a + b # 定义一个pytest类 version = 21 @pytest.mark.skipif(version>20,reason="大于2.0版本不需要在执行次用例") class Test_add: # 定义一个pytest方法 def test_add_001(self): result = add(1, 2) print(result) assert result==3 def test_add_002(self): result = add(2, 2) print(result) assert result==4 def test_add_003(self): result = add(3, 2) print(result) assert result==5 collected 3 items scripts/test_ordering.py::Test_add::test_add_001 SKIPPED (大于2.0版本不需要在执行次用例) scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (大于2.0版本不需要在执行次用例) scripts/test_ordering.py::Test_add::test_add_003 SKIPPED (大于2.0版本不需要在执行次用例) ================================ 3 skipped in 0.05s ================================
-
示例4:测试方法使用-------满足条件跳过
version = 21
@pytest.mark.skipif(version>20,reason="大于2.0版本不需要在执行次用例")
import time
import pytest
def add(a, b):
return a + b
# 定义一个pytest类
class Test_add:
# 定义一个pytest方法
def test_add_001(self):
result = add(1, 2)
print(result)
assert result==3
version = 21
@pytest.mark.skipif(version > 20, reason="大于2.0版本不需要在执行次用例")
def test_add_002(self):
result = add(2, 2)
print(result)
assert result==4
def test_add_003(self):
result = add(3, 2)
print(result)
assert result==5
collected 3 items
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED
scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (大于2.0版本不需要在执行次用例)
scripts/test_ordering.py::Test_add::test_add_003 5
============================ 2 passed, 1 skipped in 0.07s ============================
2、数据的参数化
pytest参数化实现:
- @pytest.mark.parameterize(argnames, argvalues)
- argnames 表示是 参数名字,字符串格式, 多个参数之间由逗号隔开 "username, password"
- argvalues 表示的是参数化的数据 列表格式
- [("13700001111","123124"),("13800011111","123456")]
- argname的参数个数要与argvalues里面的测试数据的个数要相同,否则会报错。
示例:
import pytest
def add(x, y):
return x + y
class TestAdd:
@pytest.mark.parametrize("x,y,expect", [(1, 2, 3), (2, 2, 4), (3, 2, 5)])
def test_add_01(self, x, y, expect):
result = add(x, y)
assert expect == result
collected 3 items
scripts/test_add_02.py::TestAdd::test_add_01[1-2-3] PASSED
scripts/test_add_02.py::TestAdd::test_add_01[2-2-4] PASSED
scripts/test_add_02.py::TestAdd::test_add_01[3-2-5] PASSED
================================= 3 passed in 0.05s =====================================
三、数据驱动
1、数据驱动介绍
概念:通过测试数据来驱动测试用例的执行。
1.1 数据驱动特点
- 数据驱动本身不是一个工业级标准的概念,因此在不同的公司都会有不同的解释。
- 可以把数据驱动理解为一种模式或者一种思想。
- 数据驱动技术可以将用户把关注点放在对测试数据的构建和维护上,而不是直接维护脚本,可以利用同样的过程对不同的数据输入进行测试。
- 数据驱动的实现要依赖参数化的技术。
1.2 数据驱动方式
- 直接定义在测试脚本中(简单直观,但代码和数据未实现真正的分离,不方便后期维护)
- 从文件读取数据,如JSON、excel、xml、txt等格式文件
- 从数据库中读取数据
- 直接调用接口获取数据源
- 本地封装一些生成数据的方法
1.3 json读取文件回顾
数据驱动实战一
1.安装:pip install ddt
2,导包
from ddt import ddt,data,unpack
3,使用ddt装饰器---示例
from ddt import ddt,data,unpack
#构造测试数据
def build_data():
pass
@ddt
class TPShopLogin2(unittest.TestCase):
@data(*build_data())
@unpack
def test01_login(self):
pass
#build_data()是定义的读取json文件的方法, 相当于是一个二维列表,[[{"username":"mike"}], [{"username":"mike11"}]]-----需要用unpack解包
#@unpack 解包 只能解包一次 解出来是一组一组数据[{"username":"mike"}] [{"username":"mike"}] 每一组数据还是一个列表 ,需要配合*进行两次解包
#*build_data() 调用函数时,函数名前面加*,表示对结果进行一次解包
#在配合@unpack 就可以进行两次解包
示例;
import json
from ddt import ddt,data,unpack
import requests
import unittest
from parameterized import parameterized
#构造测试数据
def build_data():
test_data=[]
file="../data/login.json"
with open(file,encoding="utf-8") as f:
json_data=json.load(f)
for case_data in json_data:
username=case_data.get("username")
password = case_data.get("password")
verify_code = case_data.get("verify_code")
status_code = case_data.get("status_code")
status = case_data.get("status")
msg = case_data.get("msg")
test_data.append((username,password,verify_code,status_code,status,msg))
# print("test_data".format(username,password,verify_code,status_code,status,msg))
print(test_data)
return test_data
@ddt
class TPShopLogin2(unittest.TestCase):
def setUp(self):
#实例化session对象
self.session=requests.Session()
#定义验证码接口url地址
self.url_verify="http://localhost/index.php?m=Home&c=User&a=verify"
#定义登录接口url地址
self.url_login="http://localhost/index.php?m=Home&c=User&a=do_login"
def tearDown(self):
#关闭session对象
self.session.close()
@data(*build_data())
@unpack
def test01_login(self,username,password,verify_code,status_code,status,msg):
#发送验证码请求并断言
response=self.session.get(url=self.url_verify)
self.assertEqual(200,response.status_code)
self.assertIn("image",response.headers.get("Content-Type"))
#发送登录请求并断言
login_data={
"username":username,
"password":password,
"verify_code":verify_code
}
response=self.session.post(url=self.url_login,data=login_data)
print(response.json())
self.assertEqual(status_code,response.status_code)
self.assertEqual(status,response.json().get("status"))
self.assertIn(msg,response.json().get("msg"))
if __name__ == '__main__':
unittest.main()
DDT的实现原理(重点)
ddt在使用是非常简洁,也就是两个装饰器
- @ddt 这个装饰器装饰测试类
- @data 这个装饰器装饰用例方法并传入测试数据
这两个装饰器实现的效果就是:根据传入的用例数据自动生成用例。
具体是怎么实现的呢?其实实现思路就两个步骤:
- 第一步:把传进来的用例数据保存起来
- 第二步:遍历用例数据,没遍历一条数据就动态的给测试类添加一个用例方法。
@data:做的是第一步,将转入的测试数据保存起来
@ddt:做的是第二步,遍历测试用例,给测试类动态添加用例方法
@ddt
class TestLogin(unittest.TestCase):
@data(11,12)
def test_login(self,item)
pass
分析上面的代码,首先是调用data装饰器函数,把用例数据11,12 当成参数传入进去,然后返回一个可调用对象(函数)
,在次调用返回的函数并把用例方法传入进去。
五.关联+传递参数
1.关联+传递独立参数组成的业务
处理方法:
- @pytest.fixture
- parametrize方法
- 使用全局配置文件conftest.py
- 全局变量
示例:
1.1---@pytest.fixture
- pytest不支持这种向普通的方法参数传递的过程,需要加上pytest标签说明--@pytest.fixture
1.1.1同一个脚本内部参数传递
- 加上@pytest.fixture后 可以传递了
@pytest.fixture()
def test_case01():
num1=6
return num1
def test_case02(test_case01):
num2=test_case01
print("从方法1传递的值",num2)
Process finished with exit code 0
从方法1传递的值 6
PASSED
- 如何传递一组值--列表
@pytest.fixture()
def test_case03():
dataList=[1,2,3,4]
return dataList
def test_case04(test_case03):
test_case03.append(5)
print("从方法3传入的列表",test_case03)
Process finished with exit code 0
从方法3传入的列表 [1, 2, 3, 4, 5]
PASSED
- 如何传递一组值--字典
@pytest.fixture()
def test_case03():
dataform={"username":"zhangsan","password":"123456"}
return dataform
def test_case04(test_case03):
print("从方法3传入的列表",test_case03)
Process finished with exit code 0
从方法3传入的列表 {'username': 'zhangsan', 'password': '123456'}
PASSED
1.1.2不同脚本之间参数传递
- 从另外一个文件传递参数
其他文件先返回参数
需要参数的文件先导包
#文件2--返回参数的
import pytest
@pytest.fixture()
def test_case01():
num1=60
return num1
#**********************************************************************************
#文件1--需要传递参数的
from script.data_test_02 import test_case01
def test_case05(test_case01):
num5=test_case01
print("从其他文件通过fixture传入的数据",num5)
Process finished with exit code 0
从其他文件通过fixture传入的数据 60
PASSED
1.2--@pytest.mark.parametrize
结合参数化标签来传递参数
- pytest参数化不能值转一个值,否则会报错
@pytest.mark.parametrize('num',(1))
def test_case07(num):
print(num)
--要多个值才行
@pytest.mark.parametrize('num',(1,2))
def test_case07(num):
print(num)
#文件2--返回参数的
def test_case01():
list=[1,2,3]
return list
#文件1--传递参数的
from script.data_test_02 import test_case01
@pytest.mark.parametrize('num',test_case01())
def test_case06(num):
num6=num
print("从其他文件通过parametrize传入的数据",num6)
Process finished with exit code 0
PASSED从其他文件通过parametrize传入的数据 1
PASSED从其他文件通过parametrize传入的数据 2
PASSED从其他文件通过parametrize传入的数据 3
PASSED
1.3使用全局配置文件conftest.py
- 结合配置文件conftest.py文件,这样就解决了引用/导包的麻烦
from script.data_test_02 import test_case01
通过公共的配置文件传递conftest.py
- conftest.py是pytest特有的本地测试配置文件
1.先在配置文件 中conftest.py文件中定义需要返回参数的方法---所有脚本都可以调用这个方法
2,其他文件直接引用,不需要导包
1.4全局变量
- 当前脚本所有方法都要用的,可以使用全局变量
- 其他脚本要是要全局变量,需要先引用
global_list=[1,2,3]
def test_case02():
print("全局变量",global_list)
Process finished with exit code 0
全局变量 [1, 2, 3]
PASSED
小结:
1、在当前脚本内部需要参数传递,就使用fixture
2、偶发性的需要使用其他脚本的参数
- 如果已经设置fixture------引入该文件,用fixture方法进行参数传递
- 或者使用普通函数方法传递-----结合parametrize
3、大批量的脚本需要使用相同的测试数据----数据放在conftest.py中----所有当前项目的脚本都可以直接使用,不需要引入文件
4、当前脚本需要传递某些公共的参数,不想定义fixture-----使用全局变量即可,
六.Allure测试报告
目标:
-
能够将项目生成 allure 报告
-
能够在 allure 报告上添加测试步骤
-
能够在 allure 报告上添加测试描述
-
能够在 allure 报告上添加严重级别
1. allure安装
- 在线安装 pip install allure-pytest
- 离线安装
- pycharm安装
2. allure运行脚本生成结果文件
allure使用步骤:
- 要在pytest.ini 配置文件中的addopts项中,增加一项:
--alluredir report
#report 表示的是生成报告数据存放的目录
# 添加行参数
addopts = -s --alluredir report
# 文件搜索路径
testpaths = ./scripts
# 文件名称
python_files = test_*.py
# 类名称
python_classes = Test*
# 方法名称
python_functions = test_*
- 在终端执行pytest命令 ,运行脚本
- 程序运行结束后,会在项目的report目录中生成一些json文件
3. 将测试结果文件转成 html
安装:
-
https://bintray.com/qameta/generic/allure2 下载 allure-2.6.0.zip
-
解压缩到一个目录(不经常动的目录)
-
将压缩包内的 bin 目录配置到 path 系统环境变量
-
右键我的电脑 - 属性 - 高级设置 - 环境变量 - 找到系统环境变量的path项 - 增加 allure到bin 目录
-
在命令行中敲 allure 命令,如果提示有这个命令,即为成功
使用步骤:
在保证项目中的 report 目录下有 json 文件的时候,执行以下步骤。
-
- 进入 report 上级目录执行命令
allure generate report/ -o report/html --clean
-
- report 目录下会生成 html 文件夹,html 下会有一个 index.html ,右键用浏览器打开即可。
- report 目录下会生成 html 文件夹,html 下会有一个 index.html ,右键用浏览器打开即可。
4.疑问和解答
1、addopts = -s --alluredir report 中的 --alluredir report 是什么意思?
- --alluredir 后面的 report 为测试结果文件输出的目录名
- 如果希望目录名叫 result 那么可以将命令行参数改为 --alluredir result
2、allure generate report/ -o report/html --clean 是什么意思?
- report/ 表示测试结果文件所在的目录
- -o 表示 output 输出
- report/html 表示将 index.html 报告生成到哪个文件夹
七、allure语pytest结合
1.添加测试步骤
应用场景 :
一套登录流程需要至少三个步骤,输入用户名,输入密码,点击登录。我们可以通过添加测试步 骤,让这些步骤在报告中进行体现
使用方式:
@allure.step(title="测试步骤001")
例如:在操作层中的方法上加上 @allure.step(title="测试步骤001") 装饰器
2. 添加图片描述
应用场景 :
如果我们想将某些操作过后的结果展现在报告上,可以使用添加图片描述的方法。
使用方式 在需要截图的地方添加如下代码:
allure.attach(driver.get_screenshot_as_png(), "截图", allure.attachment_type.PNG)
#截图
allure.attach(self.driver.get_screenshot_as_png(), "更新成功截图", allure.attachment_type.PNG)
3. 添加严重级别
应用场景 :
在工作中,我们会向开发人员提交很多 bug ,不同的 bug 优先级也应当不同,打开程序就崩溃, 和关于软件的页面错了一个字。就这两者而言,崩溃肯定更严重,也更需要开发人员优先修复。那 么,我可以将这些 bug 的优先级展示在报告当中。
使用方式 :
@allure.severity(allure.severity_level.BLOCKER)
在测试脚本中,增加装饰器 @allure.severity(allure.severity_level.BLOCKER)
参数有五个,也对应不同的优先级,只需要将最后一个词替换即可。
-
BLOCKER 最严重
-
CRITICAL 严重
-
NORMAL 普通
-
MINOR 不严重
-
TRIVIAL 最不严重
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?