pytest简易教程(04):fixture简介及调用
pytest简易教程汇总,详见:https://www.cnblogs.com/uncleyong/p/17982846
前言
上一篇我们介绍了固件,通过示例可以看到,一个模块中,固件会对其作用范围内的所有用例起作用;
其实这样很不灵活,比如我们只希望部分测试用例执行某个固件,通过setup和teardown是实现不了的;
但是,通过fixture就可以根据需要自定义测试用例的前置、后置操作;
fixture是通过yield来区分前后置的,前后置均可以单独存在,fixture如果有后置,前置不报错就都会执行,前置报错后置就不会执行。
fixture的优势
1、与setup、teardown类似,fixture提供了测试执行前和测试执行后的处理,但是又比setup、teardown更灵活好用,比如:fixture命名更加灵活,不局限于setup和teardown
2、conftest.py配置里可以实现数据共享,可以方便管理、修改和查看fixture函数,并且不需要import就能自动找到fixture
3、fixture可用于封装数据,也可用于封逻辑动作,使用范围非常广
fixture介绍
fixture装饰器来标记固定的工厂函数,在其他函数、类、模块或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作。
源码:
1 2 3 4 5 6 7 8 9 10 11 | def fixture( # noqa: F811 fixture_function: Optional[FixtureFunction] = None, *, scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = "function" , params : Optional[Iterable[ object ]] = None, autouse: bool = False, ids: Optional[ Union[Sequence[Optional[ object ]], Callable[[Any], Optional[ object ]]] ] = None, name: Optional[str] = None, ) -> Union[FixtureFunctionMarker, FixtureFunction]: |
方法:fixture(scope="function", params=None, autouse=False, ids=None, name=None)
常用参数:
- scope:被@pytest.fixture标记的方法的作用域,默认是function,还可以是class、module、package、session。(注:下一篇详解)
- params:用于给fixture传参,可实现数据基于fixture的数据驱动,接收一个可以迭代的对象,比如列表[]、元组()、字典列表{[],[],[]}、字典元组{(),(),()},提供参数数据供调用fixture的用例使用;传进去的参数,可以用request.param调用
- autouse:是否自动运行,是一个布尔值,默认为False不会自动执行,需要手动调用;当它为True时,作用域内的测试用例都会自动调用该fixture
- ids:用例标识id,每个ids和params一一对应,如果没有id,将从params自动产生
- name:给被@pytest.fixture标记的方法取一个别名,如果使用了name,那只能将name传入,函数名不再生效
fixture的调用
测试用例如何调用fixture呢?
函数引用/参数引用
将fixture名称作为测试用例函数/方法的参数;另外,如果fixture有返回值,必须用这种方式,否则获取不到返回值(比如:@pytest.mark.usefixtures()这种方式就获取不到返回值,详见:https://www.cnblogs.com/uncleyong/p/17957896)
函数引用:测试类中测试方法形参是测试类外被@pytest.fixture()标记的测试函数,也就是说,fixture标记的函数可以应用于测试类内部
参数引用:测试类中测试方法形参是当前测试类中被@pytest.fixture()标记的方法
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 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest .fixture() def fun(): print ( "---fixture" ) @pytest .fixture() def fun2(): print ( "---fixture2" ) def test_a(fun): print ( "--------------test_a" ) class Test01: def test_b( self , fun2): print ( "--------------test_b" ) def test_c( self , fun3): print ( "--------------test_c" ) @pytest .fixture() def fun3( self ): print ( "---fixture3" ) |
结果:
加装饰器:@pytest.mark.usefixtures(fixture_name, ...)
测试用例上加装饰器
可以多个fixture参数,放前面的先执行,放后面的后执行,也就是说,执行顺序和usefixtures后面引用顺序对应
示例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest.fixture() def fun(): print( "---fixture" ) @pytest.fixture() def fun2(): print( "---fixture2" ) def test_a(fun): print( "--------------test_a" ) class Test01: def test_b(self, fun2): print( "--------------test_b" ) @pytest.mark.usefixtures( 'fun2' , 'fun' ) def test_c(self): print( "--------------test_c" ) |
结果:先调用fun2,然后调用fun
示例二:
可以多个装饰器,先执行的放底层,后执行的放上层
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 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest.fixture() def fun(): print( "---fixture" ) @pytest.fixture() def fun2(): print( "---fixture2" ) def test_a(fun): print( "--------------test_a" ) @pytest.mark.usefixtures( 'fun' ) @pytest.mark.usefixtures( 'fun2' ) class Test01: def test_b(self): print( "--------------test_b" ) def test_c(self): print( "--------------test_c" ) |
结果
示例三:
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 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest.fixture() def fun(): print( "---fixture" ) @pytest.fixture() def fun2(): print( "---fixture2" ) def test_a(fun): print( "--------------test_a" ) class Test01: def test_b(self): print( "--------------test_b" ) @pytest.mark.usefixtures( 'fun' ) def test_c(self, fun2): print( "--------------test_c" ) |
结果:同时有装饰器和引用,装饰器先执行
测试类上加装饰器
类中所有测试用例都会调用该fixture
示例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest.fixture() def fun(): print( "---fixture" ) @pytest.fixture() def fun2(): print( "---fixture2" ) def test_a(fun): print( "--------------test_a" ) @pytest.mark.usefixtures( 'fun2' ) class Test01: def test_b(self): print( "--------------test_b" ) def test_c(self, fun): print( "--------------test_c" ) |
结果:同时有装饰器和引用,装饰器先执行
示例二:
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 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest.fixture() def fun(): print( "---fixture" ) @pytest.fixture() def fun2(): print( "---fixture2" ) def test_a(fun): print( "--------------test_a" ) @pytest.mark.usefixtures( 'fun2' ) class Test01: def test_b(self): print( "--------------test_b" ) @pytest.mark.usefixtures( 'fun' ) def test_c(self): print( "--------------test_c" ) |
结果:方法和类上都有装饰器,方法上装饰器优先执行
总结:
@pytest.mark.usefixtures('fun2')
@pytest.mark.usefixtures('fun')
等价于:
@pytest.mark.usefixtures('fun','fun2')
自动适配:fixture设置autouse=True
影响作用域内所有用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest.fixture() def fun(): print( "---fixture" ) @pytest.fixture(autouse=True) def fun2(): print( "---fixture2" ) def test_a(): print( "--------------test_a" ) class Test01: def test_b(self): print( "--------------test_b" ) def test_c(self): print( "--------------test_c" ) |
结果:每个测试用例都执行了fun2
fixture嵌套
不能用@pytest.mark.usefixtures
示例:两个fixture,fun依赖login
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : 韧 # @wx :ren168632201 # @Blog :https://www.cnblogs.com/uncleyong/ import pytest @pytest.fixture() def login(): print( "---登录" ) @pytest.fixture() def fun(login): print( "---fun" ) # 下面写法报错 # @pytest.fixture() # @pytest.mark.usefixtures(login) # def fun(): # print("---fun") # @pytest.mark.usefixtures(fun) # 报错 def test_a(fun): print( "--------------test_a" ) |
结果:
__EOF__

关于博主:擅长性能、全链路、自动化、企业级自动化持续集成(DevTestOps)、测开等
面试必备:项目实战(性能、自动化)、简历笔试,https://www.cnblogs.com/uncleyong/p/15777706.html
测试提升:从测试小白到高级测试修炼之路,https://www.cnblogs.com/uncleyong/p/10530261.html
欢迎分享:如果您觉得文章对您有帮助,欢迎转载、分享,也可以点击文章右下角【推荐】一下!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2022-02-23 答疑记录:jmeter从返回的html中提取指定内容