IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> pytest测试框架系列 - Pytest Fixture和conftest.py还能这样使用? -> 正文阅读

[开发测试]pytest测试框架系列 - Pytest Fixture和conftest.py还能这样使用?

前言

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 函数说明

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_<fixturename>`` and then use
        ``@pytest.fixture(name='<fixturename>')``.
    """
    """
    翻译:
	 可以使用此装饰器(带或不带参数)来定义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参数详解

使用语法:

@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"

# _*_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"

示例:

# _*_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"

示例:

# _*_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
    示例:
# _*_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走(注意使用)
    示例:
# _*_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时:

# _*_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的示例:

# _*_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"])

执行结果:
在这里插入图片描述

fixture之yield实现teardown

  • 用fixture实现teardown并不是一个独立的函数,而是用 yield 关键字来启用teardown操作

示例:

conftest.py

# _*_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")
    yield
    print("我是测试用例清理操作!")

test_01.py

# _*_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 测试用例")

执行结果:
在这里插入图片描述

问题:

当我们多个测试用例文件(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文件,逐层往上查找

示例:

  • 项目目录
case
│  conftest.py
│  __init__.py
│
├─case01
│      conftest.py
│      test_01.py
│      __init__.py
│
└─case02
        conftest.py
        test_02.py
        __init__.py

case/conftest.py

# _*_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

# _*_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

# _*_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

# _*_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

# _*_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的测试函数使用

以上为内容纯属个人理解,如有不足,欢迎各位大神指正,转载请注明出处!

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-07-05 20:28:17  更:2021-07-05 20:28:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 18:40:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码