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装饰器来标记固定的工厂函数,在其他函数、类、模块或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作。
源码:
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()标记的方法
#!/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后面引用顺序对应
示例一:
#!/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
示例二:
可以多个装饰器,先执行的放底层,后执行的放上层
#!/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")
结果
示例三:
#!/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
示例一:
#!/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")
结果:同时有装饰器和引用,装饰器先执行
示例二:
#!/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
影响作用域内所有用例
#!/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
#!/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
欢迎分享:如果您觉得文章对您有帮助,欢迎转载、分享,也可以点击文章右下角【推荐】一下!