## 前言 Fixture是pytest的非常核心功能之一,在不改变被装饰函数的前提下对函数进行功能增强,经常用于测试用例前置和后置工作。与setup/teardown类似,但更强大灵活。 ## fixture的优势 - fixture命名方式灵活,不局限于 setup 和teardown 那几个命名规则 - conftest.py 配置里可以实现数据共享,能够自动搜索需要的fixture - fixture 配置不同的参数可以轻松实现跨文件、session会话共享 ## fixture工作原理 - 在普通函数上使用@Pytest.fixture()装饰器,声明函数为一个fixture函数 - 如果测试用例函数的参数列表中存在fixture的函数名或者使用@pytest.mark.usefixtures(fixture_name) - 在测试执行阶段,pytest执行用例之前执行fixture函数功能 - 如果fixture装饰的函数无返回值,相当于用例前置操作,否则相当于传参 - 如果fixture设置了后置操作,则用例执行完成后进行执行 ## fixture搜索顺序 - 第一步:优先搜索测试所在的模块 - 第二步:搜索模块同一文件路径下的conftest.py - 第三步:找不到再搜索上一层的conftest.py,直到项目根目录 ## fixture 函数说明 ```python def fixture( fixture_function: Optional[_FixtureFunction] = None, *, scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = "function", params: Optional[Iterable[object]] = None, autouse: bool = False, ids: Optional[ Union[ Iterable[Union[None, str, float, int, bool]], Callable[[Any], Optional[object]], ] ] = None, name: Optional[str] = None, ) -> Union[FixtureFunctionMarker, _FixtureFunction]: """Decorator to mark a fixture factory function. This decorator can be used, with or without parameters, to define a fixture function. The name of the fixture function can later be referenced to cause its invocation ahead of running tests: test modules or classes can use the ``pytest.mark.usefixtures(fixturename)`` marker. Test functions can directly use fixture names as input arguments in which case the fixture instance returned from the fixture function will be injected. Fixtures can provide their values to test functions using ``return`` or ``yield`` statements. When using ``yield`` the code block after the ``yield`` statement is executed as teardown code regardless of the test outcome, and must yield exactly once. :param scope: The scope for which this fixture is shared; one of ``"function"`` (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``. This parameter may also be a callable which receives ``(fixture_name, config)`` as parameters, and must return a ``str`` with one of the values mentioned above. See :ref:`dynamic scope` in the docs for more information. :param params: An optional list of parameters which will cause multiple invocations of the fixture function and all of the tests using it. The current parameter is available in ``request.param``. :param autouse: If True, the fixture func is activated for all tests that can see it. If False (the default), an explicit reference is needed to activate the fixture. :param ids: List of string ids each corresponding to the params so that they are part of the test id. If no ids are provided they will be generated automatically from the params. :param name: The name of the fixture. This defaults to the name of the decorated function. If a fixture is used in the same module in which it is defined, the function name of the fixture will be shadowed by the function arg that requests the fixture; one way to resolve this is to name the decorated function ``fixture_
`` and then use ``@pytest.fixture(name='
')``. """ """ 翻译: 可以使用此装饰器(带或不带参数)来定义fixture功能。 fixture功能的名称可以在后面使用引用它会在运行测试之前调用它:test模块或类可以使用 pytest.mark.usefixtures(fixturename标记)。 测试功能可以直接使用fixture名称作为输入参数,在这种情况下,夹具实例从fixture返回功能将被注入。 fixture可以使用``return`` or``yield`` 语句返回测试函数所需要的参数值,在``yield``后面的代码块 不管测试的执行结果怎么样都会执行 :arg scope: scope 有四个级别参数 "function" (默认), "class", "module" or "session". :arg params: 一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它 :arg autouse: 如果为True,自动执行fixture函数,所有函数都可以使用。 如果为False(默认值) 则手动使用fixture才能调用 :arg ids: 每个字符串id的列表,每个字符串对应于params 这样他们就是测试ID的一部分。 如果没有提供ID它们将从params自动生成 :arg name: fixture的名称。 默认为装饰函数的名称。 如果设置了name的值,在使用fixture时需要 使用设置的name,否则无法识别 """ ``` ## fixture参数详解 使用语法: ```python @pytest.fixture(scope = "function",params=None,autouse=False,ids=None,name=None) def login(): print("我是login函数") ``` ### scope 参数 - 说明:可以认为是fixture的作用域,默认:function,还有class、module、package、session四个 - 区别: 取值 | 范围|说明| -------- | -----|----- function| 函数级|每一个函数或方法都会调用 class| 类级|每个测试类只运行一次 module| 模块级|每一个.py文件调用一次 session| 会话级|每次会话只需要运行一次,一般用于打开浏览器、启动APP、登录等操作 #### **关注点** - fixture可以给函数和类使用 - fixture通过测试用例参数方式使用,这样fixture的返回值可以通过fixture名称作为参数传递给测试用例,也可以使用@pytest.mark.usefixtures("login")方式,但无法给测试用例传递fixture的返回值 - fixture函数内可以调用其他fixture函数,必须要通过函数参数方式 - 非测试用例的函数无法使用fixture 作用范围示例: #### **scope = "function"** ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 14:39 # @Author : king # @File :test_fixture.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(scope="function") def login(): print("我是login函数。。") return "king" # fixture内调用其他fixture @pytest.fixture(scope="function") def login_01(login): print("我是调用了 login的fixture函数") # 通过参数方式使用fixture def test_01(login): print("我是 test_01 测试用例\n") # 通过@pytest.mark.usefixtures("login")调用fixture @pytest.mark.usefixtures("login") def test_02(): print("我是 test_02 测试用例\n") # 通过参数方式使用调用其他fixture的fixture def test_03(login_01): print("我是 test_03 测试用例\n") # 给类使用fixture @pytest.mark.usefixtures("login") class TestFixture: def test_one(self): print("我是类里面的 test_one 测试用例") def test_two(self): print("我是类里面的 test_two 测试用例") # 非test开头函数调用fixture def reg_01(login): print("我是reg函数\n") # 非test开头函数使用@pytest.mark.usefixtures("login")调用fixture @pytest.mark.usefixtures("login") def reg_02(): print("我是reg函数\n") if __name__ == '__main__': pytest.main(["-s", "test_fixture.py"]) ``` 执行结果为:  #### **scope = "class"** 示例: ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 15:35 # @Author : king # @File :test_fixture_class.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(scope="class") def login(): print("我是login函数。。") return "king" # 通过参数方式使用fixture def test_01(login): print("我是 test_01 测试用例\n") # 通过参数方式使用fixture def test_02(login): print("我是 test_02 测试用例\n") @pytest.mark.usefixtures("login") class TestFixture: def test_one(self): print("我是类里面的 test_one 测试用例") def test_two(self): print("我是类里面的 test_two 测试用例") if __name__ == '__main__': pytest.main(["-s", "test_fixture_class.py"]) ``` 执行结果:  #### **scope = "module"** 示例: ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 16:52 # @Author : king # @File :test_fixture_module.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(scope="module") def login(): print("我是login函数。。") return "king" # 通过参数方式使用fixture def test_01(login): print("我是 test_01 测试用例\n") # 通过参数方式使用fixture def test_02(login): print("我是 test_02 测试用例\n") @pytest.mark.usefixtures("login") class TestFixture: def test_one(self): print("我是类里面的 test_one 测试用例") def test_two(self): print("我是类里面的 test_two 测试用例") if __name__ == '__main__': pytest.main(["-s", "test_fixture_module.py"]) ``` 执行结果为:  #### **scope = "session"** - 注意:session代表会话级,就是从启动测试到结束测试,看作为一次session会话,scope = "session"使用到后面conftest.py详细讲解 ### params 参数 - fixture的可选形参列表,支持列表传入 - params 参数包含几个,调用时就会执行几次 - 可与参数ids一起使用,作为每个参数的标识,详见ids - 需要使用时,参数调用写法固定为:Request.param 示例: ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 17:13 # @Author : king # @File :test_fixture_params.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(params=[1, 2, 3, 4, 5]) def login(request): print("我是login函数。。") return request.param # 通过参数方式使用fixture def test_01(login): print("我是 test_01 测试用例-params- {}\n".format(login)) if __name__ == '__main__': pytest.main(["-s", "test_fixture_params.py"]) ``` 执行结果:  ### autouse 参数 - 默认False - 如果设置为True,则每个测试函数都会自动调用该fixture,无需传入fixture函数名,作用范围跟着scope走(注意使用) 示例: ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 17:25 # @Author : king # @File :test_fixture_autouse.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(autouse=True) def login(): print("我是login函数。。") # 通过参数方式使用fixture def test_01(): print("我是 test_01 测试用例\n") if __name__ == '__main__': pytest.main(["-s", "test_fixture_autouse.py"]) ``` 执行结果:  ### ids 参数 - 用例标题,需要与params配合使用,一对一关系 **未配置ids时:** ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 17:29 # @Author : king # @File :test_fixture_ids.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(params=[1, 2, 3]) def login(request): return request.param # 通过参数方式使用fixture def test_01(login): print("我是 test_01 测试用例\n") if __name__ == '__main__': pytest.main(["-s", "test_fixture_ids.py"]) ``` 执行结果:  **配置了ids的示例:** ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 17:29 # @Author : king # @File :test_fixture_ids.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(params=[1, 2, 3], ids=["case01", "case02", "case03"]) def login(request): return request.param # 通过参数方式使用fixture def test_01(login): print("我是 test_01 测试用例\n") if __name__ == '__main__': pytest.main(["-s", "test_fixture_ids.py"]) ``` 执行结果:  **问题:** 当我们多个测试用例文件(test_*.py)的所有用例都需要用登录、打开浏览器、启动APP等功能来作为前置操作,那就不能把登录、打开浏览器、启动APP功能写到某个用例文件,如何解决呢? 解决方案:引入conftest.py文件,为了解决上述问题,单独管理一些全局的fixture ## conftest.py使用 说明: - pytest会默认读取conftest.py里面的所有fixture - conftest.py 文件名称是固定的,不能随意改动 - conftest.py只对同一个package下的所有测试用例生效,并且有__init__.py文件 - 不同目录可以有自己的conftest.py,一个项目中可以有多个conftest.py - pytest会自动查找项目中的conftest.py文件,逐层往上查找 示例: - 项目目录 ```bash case │ conftest.py │ __init__.py │ ├─case01 │ conftest.py │ test_01.py │ __init__.py │ └─case02 conftest.py test_02.py __init__.py ``` case/conftest.py ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 18:04 # @Author : king # @File :conftest.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(scope="session") def login(): print("我是case目录的login") @pytest.fixture(scope="session") def open_browser(): print("我是case目录的 open_browser") ``` case01/conftest.py ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 18:06 # @Author : king # @File :conftest.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(scope="session") def login(): print("我是case01目录的login") ``` case01/conftest.py ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 18:04 # @Author : king # @File :test_01.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 def test_01(login): print("我是case01 里面test_01 测试用例") def test_02(open_browser): print("我是case01 里面test_02 测试用例") ``` case02/conftest.py ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 18:07 # @Author : king # @File :conftest.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 import pytest @pytest.fixture(scope="session") def _login(): print("我是case02 目录的login") ``` case02/test_02.py ```python # _*_coding:utf-8 _*_ # @Time :2021/7/3 18:04 # @Author : king # @File :test_02.py # @Software :PyCharm # @blog :https://blog.csdn.net/u010454117 # @WeChat Official Account: 【测试开发知识库】 def test_02(login): print("我是case02的 test_02 测试用例") ``` 在case目录下,执行 `pytest -s`  **注意点** - 外层的fixture不能调用内层的fixture - 不同包下面的fixture只能当前包使用,不能被其他包使用,例如case01下面的fixture不能被case02的测试函数使用 ---- 以上为内容纯属个人理解,如有不足,欢迎各位大神指正,转载请注明出处! >**如果觉得文章不错,欢迎关注CSDN和微信公众号** > >微信公众号: 
微信关注我们
原文链接:https://blog.51cto.com/king15800/2973429
转载内容版权归作者及来源网站所有!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
相关文章
发表评论
资源下载
更多资源优质分享App
近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。
Mario
马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。
Apache Tomcat
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Sublime Text
Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。