pytest fixture 参数化,pytest框架fixture的作用
pytest夹具的详细使用(更灵活先进的前/后处理方法)_wx6131dcc8eea14的技术博客_博客
一、fixture基本操作介绍虽然pytest在unittest的两组前置后置方法的基础上提供了更全面的五组前置后置方法,但是这些方法对于其对应的整个作用域都是全局有效的。
如果有以下场景:用例1需要先登录,用例2不需要登录,用例3需要先登录。显然不是装拆就能实现的。
Fixture,测试框架的精髓,允许我们随意定制测试用例的前置后置方法。
Fixture是一种机制,pytest通过这种机制将测试前后准备和清理的代码与核心测试逻辑分离开来。
1.基本形式和用法:@pytest.fixture () decorator用于声明一个函数是fixture,这个fixture的名称默认为函数名,也可以自己指定名称(详见参数名说明)
如果测试用例的参数表中包含fixture的名称,pytest会根据名称检测fixture,并在测试函数运行之前执行。
Fixture可以完成测试任务或者向测试用例返回数据。
导入pytest
@ pytest . fixture(scope= function ,params=None,autouse=False,ids=None,name=None)
定义func_01():
打印(“这定义了一个简单的夹具”)
返回“结果”
定义测试_01(函数_01):
Print(type(func_01),func_01) #结果
if __name__==__main__ :
pytest.main()
2.检测顺序:检测顺序是:当前测试类模块的当前包中的confitest.py(。py文件)、父包中confitest.py根目录下的confitest.py。
3.存储位置可以放在测试用例自己的测试文件中。如果您想要多个测试文件共享fixture,您可以将它放在一个公共目录中,并创建一个新的conftest.py单击查看它,并将fixture放入其中。4.关于如何调用fixture的注意事项:如果不是测试用例,无论哪种调用方法都会生效(参考func_006)。如果它没有被传递到fixture中,就不会被执行。
1)参数传递:
将fixture函数名作为参数传递给用例(不带引号的函数名)
支持多个,并且支持在fixture相互调用时向fixture传递参数。
返回值:在fixture被执行后,返回值将被赋给用例的参数名。如果没有返回值,默认为None。
2)装饰器传递引用:
支持多个,但不支持在夹具相互调用时向夹具传递参数。
返回值:无法获取
第一种类型:传入名称@ pytest . mark . use fixtures( fixure 1 , fixure2 )(字符串格式,带引号)
类型2:使用@pytest.mark.usefixture()可以叠加多个,第一个执行的放在底层,第二个执行的放在顶层。
查看代码
3)autouse=True,自动调用。有关详细信息,请参见下一节:其他参数的使用。
5 .夹具实例化顺序。高级作用域的fixturess在低级作用域的fixture之前被实例化(会话包模块类函数)。具有相同作用域的fixture遵循测试函数中声明的顺序,遵循fixture之间的依赖关系[fixture_A中的依赖关系fixture_B首先被实例化,然后到fixture _ A实例化] (autouse=True)。自动使用的fixture在显式使用(传递参数或修饰)fixture之前会实例化上述规则,这是基本前提。当不同级别的fixtures相互调用时,实例化序列会很复杂和麻烦:(慎用)
导入pytest
订单=[]
@pytest.fixture(scope=session )
def s1():
order.append(s1 )
@pytest.fixture(scope=session )
def s2():
order.append(s2 )
@pytest.fixture(scope=session )
def s3():
order.append(s3 )
@pytest.fixture(scope=session )
def s4():
order.append(s4 )
@pytest.fixture(scope=session )
定义s5(s7):
order.append(s5 )
@pytest.fixture(scope=session )
def s6():
order.append(s6 )
@pytest.fixture(scope=session )
def s7():
order.append(s7 )
@pytest.fixture(scope=module )
定义m1():
order.append(m1 )
@pytest.fixture(scope=module )
定义m2(s5):
order.append(m2 )
@pytest.fixture(scope=module )
定义m3(s4):
order.append(m3 )
@pytest.fixture
定义f1(s2,f3):
order.append(f1 )
@pytest.fixture
定义f2(m2,s3):
order . append(“F2”)
@pytest.fixture
定义f3(s6):
order . append(“F3”)
定义测试订单(f2,f1,m3,m1,s1):
print(order) # [s1 , s3 , s2 , s4 , s7 , s5 , s6 , m3 , m1 , m2 , f2 , f3 , f1]
if __name__==__main__ :
pytest.main()视图代码
可以先把继承图画出来,这样就清楚了。按级别找就行了:
在实例化基本规则的前提下,不同层次的fixture之间可能会有相互调用,所以存在一个层次的依赖深度,如图:
1.必须首先执行所有会话级别,然后确定该级别的夹具顺序:
1)首先运行第一级的会话级,然后运行s1
2)按照来话(f2,f1,m3,m1,s1)来话顺序依次搜索第二级,得到s3 s2 s4。
3)根据传入(f2,f1,m3,m1,s1)传入顺序搜索第三级,得到(s5依赖于相同的作用域级s7)s7 s5 s6。
2.接下来,运行模块级
1)第一层是来料订单m3 m1。
2)按照(f2,f1,m3,m1,s1)的来话顺序依次搜索第二级,得到m2。
3.运行功能级别
1)第一个级别在传入顺序f2 f3 f1中(f1依赖于相同的作用域级别f3)
经过以上过程,得到最终结果:[S1 , S3 , S2 , S4 , S7 , S5 , S6 , M3 , M1 , M2 , F2 , F3 , F1] II。范围参数的详细说明(2
Fixture可以互相调用,但是要注意,如果级别不同,下级可以调用上级,上级不能调用下级。
-function:每个调用fixture的函数或方法在执行前都会执行一次,销毁代码会在测试用例执行后运行。
-class:每个类只被调用一次。一个类中可以有多个用例,但是在最早运行的用例之前只能有一次(每个类外函数用例也将被调用一次)
-模块:每个。py文件被调用一次,这个模块中调用这个fixture的第一个用例在执行前只运行一次。
-session:一次调用多个文件,可以跨文件调用。py文件,并且每个。py文件是一个模块。
1.scope=function功能级别(默认级别)最基本的夹具
1.实施时间
每一个调用fixture的函数或方法在执行前都会执行一次,销毁代码会在测试用例执行后运行。
2.固定物可以互相调用(参考test_002的login_and_logout)
1)fixture可以像测试用例的参数一样调用其他fixture,并获取它们的返回值。
2)多个fixture的执行顺序与测试用例调用的顺序相同。
3)只支持参数传入fixture,不支持装饰器传入参数代码:
导入pytest
@pytest.fixture
定义登录():
打印(“打开浏览器”)
返回“chrome”
@pytest.fixture()
定义注销():
打印(“关闭浏览器”)
@pytest.fixture()
DEFIN _ AND _ LOGOUT (LOGOUT,LOGOUT):相互调用# fixture。支持多个调用。执行顺序是:loguot login login _ and _ logout。
打印(f 首先打开{登录},然后关闭它)
返回f“{ log in } { logout }”
Test _ 005(登录):#第一种参数:夹具名称作为参数传递======================================================
print(f005: login={login} )
类测试登录:
def test_001(自己,登录):
print(f001: login={login} )
Test _ 003 (self,login,logout): #支持多次转移,执行顺序为来话顺序:login logout test_003。
print(f 003:log in={ log in } logout={ logout } )
def test_002(自己,登录_和_注销):
print(f002:登录和注销={登录和注销} )
def test_004(自身):
Print(004:未传入,不会执行其他什么fixture)
@ py test . mark . use fixtures( log in , logout) #第二种参数:decorator参数,fixture的str,无法得到返回值========
def test_005(自身):
Print(f005:这样就不能通过传递参数来获得fixture的返回值)
@pytest.mark.usefixtures(登录,注销)
def func_006(自身):
Print(006:不是测试用例,即使修饰也不会执行fixture )
if __name__==__main__ :
pytest.main()视图代码
2.scope=class class level 1。通话模式:
与功能相同
2.运行时间:
1)类外的独立函数用例执行前会执行一次,参考测试_006
2)类中有用例调用了夹具,则会在最先调用的那个用例执行前执行一次(参考test_002),该类下其他调用了固定装置的用例不再执行(参考test_003)
3)未调用该固定装置的类和函数,不会运行
2 .夹具相互调用规则
1)类级可以调用类级,参考测试_004
2)函数级可以调用类级,参考测试_008
3)类级不可以调用函数级,参考测试_007代码:
导入pytest
@pytest.fixture(scope=class )
定义登录():
打印(打开浏览器-类级别夹具)
返回"铬合金"
@pytest.fixture()
定义注销():
打印(关闭浏览器-函数级夹具)
@pytest.fixture(scope=class )
定义类_使用类(登录):
打印(fclass_use_class -类级可以调用类级)
返回f"{登录} "
@pytest.fixture()
定义函数_使用_类(登录):
print(ffunction_use_class -函数级调用类级)
@pytest.fixture(scope=class )
定义类使用功能(注销):
打印(f 错误示范,类级不可以调用函数级)
def test_006(登录):
print(f006: login={login} )
类测试登录:
def test_001(自己,注销):
print(f001: login={logout}调用普通函数级)
def test_002(自己,登录):
print(f002:logout={login}调用类级,该类中注册只会在这里运行一次)
def test_003(自己,登录,注销):
print(f 003:登录={ log in }注销={ logout }调用类级和函数级,该类中类级注册不会再运行)
@ pytest。马克。使用固定装置( class _ use _ class )
def test_004(self,class_use_class):
打印(f004: class_use_class调用类级-类再调用类级登录,运行过了不会再运行)
# def test_004(self,class_use_class):
# print(f004: class_use_ )
def test_007(self,class_use_function):
print(f 007:class _ use _ function={ class _ use _ function }错误示范,类级不可以调用函数级)
def test_008(self,function_use_class):
print(f008: function_use_class调用函数级-函数级再调用类级登录,运行过了不会再运行)
def test_005(自身):
打印(f’005:未传入任何夹具,哪个级别都与我无关)
类别测试夹具:
def test_009(自身):
打印( 009:未传入任何夹具,哪个级别都与我无关)
if __name__==__main__ :
pytest.main()视图代码
3 .作用域=模块模块级1.调用方式:
和功能一样
2.运行时机:
每一个。巴拉圭文件调用一次,该模块内最先执行的调用了该固定装置的用例执行前运行且只运行一次(如测试_006测试_001测试_003)
2 .夹具相互调用规则
1)类级可以调用模块级,参考测试_005
2)函数级可以调用模块级,参考测试_008
3)模块级不可以调用函数级,和类级参考测试_004测试_007代码:
导入pytest
@pytest.fixture(scope=module )
def open():
打印(打开电脑-模块级别夹具)
返回"窗口"
@pytest.fixture(scope=class )
定义登录():
打印(打开浏览器-类级别夹具)
返回"铬合金"
@pytest.fixture()
定义注销():
打印(关闭浏览器-函数级夹具)
@pytest.fixture(scope=module )
定义模块_使用_类(登录):
打印(f 错误示范,模块级不可以调用类级)
返回f"{登录} "
@pytest.fixture(scope=module )
定义模块使用功能(注销):
打印(f 错误示范,模块级不可以调用函数级)
返回f"{注销} "
@pytest.fixture()
定义函数_使用_模块(打开):
打印(f 功能使用模块-函数级调用模块级)
@pytest.fixture(scope=class )
定义类使用模块(打开):
打印(f 类_使用_模块-类级调用模块级)
def test_006(登录):
print(f006: login={login} )
类测试登录:
def test_001(自身,开放):
print(f001: open={open}调用模块级)
def test_002(自己,登录):
print(f002:login={login}调用类级)
def test_003(自我,打开,登录,注销):
print(f 003:open={ open }登录={ log in }注销={ logout }调用模块级、类级和函数级)
@ pytest。马克。使用夹具( module _ use _ class )
def test_004(自身):
Print(f004: module_use_class错误演示,模块级不能调用类级)
def test_007(self,module_use_func):
Print(f007: module_use_func错误演示,模块级无法调用函数级)
def test_008(自身,函数_使用_模块):
打印(f008:功能_使用_模块)
def test_005(自身,class_use_module):
打印(f005: class_use_module )
类别TestNoFixture:
def test_009(自身):
Print(009:没有传入夹具,哪一级与我无关)
if __name__==__main__ :
pytest.main()视图代码
4.scope=sessionfixture是会话级的,可以跨会话调用。py模块。运行一个程序只会调用一次。
也就是说,当我们有多个用例。py文件,如果多个用例只需要调用fixture一次,可以设置为scope=session ,作为全局fixture写入conftest.py文件。
Conftest.py在点击查看文件名时是固定的,pytest会自动识别文件。
当它被放在项目的根目录中时,可以被全局调用。如果它放在一个包中,它将在该包中有效。
三。其他参数介绍1.params是一个可选的参数列表,它会导致fixture修饰的测试用例以列表中的每个列表项为参数多次调用fixture函数。
1.fixture可以带参数,params支持列表;
2.默认值为无;
3.对于param中的每个值,fixture将调用并执行一次,就像执行for循环一样,遍历PARMS中的值一次。
在pytest中,有一个内置的fixture,叫做request,代表fixture的调用状态。该请求有一个字段param,它以类似于@ pytest . fixture(param=tasks _ list)的方式传递给fixture。在fixture中,request.param用作要调用的测试函数的返回值。tasks_list包含多少元素,fixture就会被调用几次,作用于每个使用的测试函数。
下面的fixture和测试用例执行三次,相当于三个测试用例,比如:测试三组账号密码登录,登录用例是一个,但是每次数据都不一样。
导入pytest
tasks_list=[(10,11),(20,22),(33,33)]
@ pytest . fixture(params=tasks _ list)
定义测试数据(请求):
Print(ffixture gets:帐号:{request.param[0]},密码:{request.param[1]} )
返回请求. param
类别测试数据:
定义测试_1(自身,测试_数据):
打印(用例:,测试数据)
if __name__==__main__ :
pytest.main()
2.idsids通常可以与params一起使用。如果不指定id,pytest将在输出时自动生成一个ID作为测试ID:
当参数列表项为数字、字符串、布尔值和无时,列表项本身将用于表示测试ID,例如[true 1][true 2][xxoo][123][无]。对于其他对象,pytest会根据参数名创建一个字符串,[test_data0] [test_data1],如params中的截图所示,可以自定义使用ids关键字参数指定测试ID,如@ pytest . fixture(param=tasks _ list,ids=task _ ids)。ID可以是pytest生成任务ID的列表或函数。导入pytest
data_list=[(10,11),(20,22),(33,33)]
@ pytest . fixture(params=data _ list,ids=[a , b , c])
定义测试数据(请求):
Print(ffixture gets:帐号:{request.param[0]},密码:{request.param[1]} )
返回请求. param
类别测试数据:
def test_1(self,tes_data):
打印(用例:,tes_data)
if __name__==__main__ :
pytest.main()
3 .未启用自动使用默认False
用例多的时候,每次转移fixture都会很麻烦。夹具中有一个参数autouse,默认情况下,该参数不会被False打开。可以设置为True来开启自动使用fixture的功能,这样用例就不用每次都传递参数了。
Autouse设置为True,这将自动调用fixture函数。不需要传递参数,作用域跟在作用域后面(小心使用)。
导入pytest
@pytest.fixture(scope=module ,autouse=True)
def test1():
打印(“开始模块执行”)
@pytest.fixture(scope=class ,autouse=True)
def test2():
打印(“开始执行类”)
@ pytest . fixture(scope= function ,autouse=True)
def test3():
打印(“开始执行功能”)
定义测试_a():
打印(-用例A执行-)
定义测试_d():
打印(-用例D执行-)
类测试用例:
定义测试_b(自身):
打印(-用例B执行-)
定义测试_c(自身):
打印(-用例C执行-)自动使用fixture。
==========================================================================测试环节开始===========================测试环节开始=====================================================测试环节开始
平台win32 - Python 3.8.0,pytest-6.2.5,py-1.11.0,pluggy-1 . 0 . 0-E:\ Python 3.8 \ Python . exe
cachedir:pytest_cache
rooir:d:\ code \ automated test \ py test _ test,配置文件:pytest.ini,testpaths:/dir01/dir01 _测试. py
收集了4个项目
dir01/dir01_test.py:测试_a
开始执行模块
开始执行类
开始执行功能
-用例A的执行-
通过
dir01/dir01_test.py:测试_d
开始执行类
开始执行功能
-用例D的执行-
通过
dir 01/dir 01 _ test . py:TestCase:test _ b
开始执行类
开始执行功能
-用例B的执行-
通过
dir 01/dir 01 _ test . py:TestCase:test _ c
开始执行功能
-执行用例C-
通过
=================================================================================================================================通行证================================================
4.4.namefixture的重命名默认为fixture修饰的函数名,但是pytest也允许fixture的重命名。如果使用name,则只能传入name,函数名不再生效。
四。夹具1操作后的拆卸。前几章是使用yield的前操作,后操作需要使用python的yield实现。yield语法的解释点在这里:迭代器生成器。
如果yield前面的代码,也就是setup部分,已经抛出异常,yield之后的teardown内容将不会被执行。如果测试用例抛出异常,yield后的teardown内容仍然会正常执行import pytest。
@pytest.fixture(scope=session )
def open():
#整个会话操作前设置
打印(===打开浏览器==)
Test=测试变量是否返回
屈服试验
#整个会话操作后拆卸
打印(==关闭浏览器==)
@pytest.fixture
定义登录(打开):
#方法级操作前设置
打印(f 输入账号,登录{open} 输入密码)
Name===我是账号==
Pwd====我就是密码==
年龄===我年龄==
#返回变量
产量名称、密码、年龄
#方法级操作后拆卸
打印(“登录成功”)
def test_s1(登录):
打印(==用例1==)
#返回的是一个元组
打印(登录)
#分别给不同的变量赋值
姓名、密码、年龄=登录名
打印(姓名、密码、年龄)
在名称中声明“帐号”
断言pwd中的“密码”
断言年龄中的“年龄”
def test_s2(登录):
打印(==用例2==)
打印(登录)
if __name__==__main__ :
pytest.main()
2.使用request.addfinalizer终端函数实现yield是返回数据和暂停,后面的操作是yield。
最后一个函数用return返回,最后一个函数的后操作在前面和return中间。
如果request.addfinalizer()前面的代码,也就是setup部分抛出了异常,那么request.addfinalizer()的teardown内容就不会被执行(类似yield,应该是最近新版本改的比较一致)。您可以声明多个终止函数并调用import pytest。
@pytest.fixture(scope=module )
def test_addfinalizer(请求):
#操作前设置
打印(===打开浏览器==)
test=test_addfinalizer
定义fin():
#操作后拆卸
打印(==关闭浏览器==)
request.addfinalizer(fin)
#返回前面操作的变量
返回测试
def test _ an thor(test _ add finalizer):
Print(==最新用例==,test_addfinalizer)
if __name__==__main__ :
pytest.main()
参考:
回回回a
小菠萝
全栈测试开发日志
转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。