【python自动化】pytest系列(下)

【python自动化】pytest系列(下)_第1张图片

pytest系列文章一共有四篇,本文为第三篇。

公众号:梦无矶的测试开发之路,回复pytest可以领取对应资料

本章知识点

文章目录

    • Pytest之fixture
      • (1)fixture实现前/后置
      • (2)fixture数据传递
      • (3)fixture全局共享机制conftest.py
      • (4)fixture嵌套

Pytest之fixture

示列代码

使用装饰器的方式,scope参数是代表指定作用域的

@pytest.fixture(scope='function')
    def test_01(self):
        print("test001")

源码分析

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]:

可以简化为如下:

@pytest.fixture(scope="", params="", autouse="", ids="", name="")

scope:表示的是@pytest.fixtur标记方法的作用域,function(默认),class,module,package/session

params:可迭代参数,支持列表[],元组(),字典列表[{},{},{}],字典元组({}.{},{})

autouse=True:自动执行,默认为False,不会自动执行,需要手动调用

ids:当使用params参数化时,给每一个值设置一个变量名,用的少

name:给被@pytest.fixtur标记的方法取一个别名

scope参数为session:所有测试.py文件执行前执行一次

scope参数为module:每一个测试.py文件执行前都会执行一次conftest文件中的fixture

scope参数为class:每一个测试文件中的测试类执行前都会执行一次conftest文件中的

scope参数为function:所有文件的测试用例执行前都会执行一次conftest文件中的fixture

(1)fixture实现前/后置

四个作用域

1、测试函数 function

2、测试类 class

3、测试模块 module

4、测试会话 session

默认为function

源码查看

: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.

① 只需要在用例代码的参数中加入前置方法名即可完成前置操作

示列代码一:

class Test001():

    @pytest.fixture(scope='function')
    def beferFunction(self):
        print("fixture的function")

    @pytest.fixture(scope='class')
    def beferClass(self):
        print("fixture的class")

    @pytest.fixture(scope='module')
    def beferModule(self):
        print("fixture的module")

    def test_04(self,beferFunction,beferClass,beferModule):
        print("测试用例004")

执行结果

============================= test session starts =============================
collecting ... collected 1 item

test_001.py::Test001::test_04 fixture的module
fixture的class
fixture的function
PASSED                                     [100%]测试用例004


============================== 1 passed in 0.03s ==============================

执行顺序:module --> class --> function --> 用例

类级别的前后置,一定要写到第一个用例上, 写在最后一个上的话,执行时不会检测到有类级别前置,所以不会执行。检测到 有类级别前置,才会执行;

示列代码二:

② 使用@pytest.mark.usefixtures(“前/后置函数名”)

import pytest

@pytest.fixture(scope="function")
def fixture_fun():
    print("function级别的前置操作")
    yield
    print("function级别的后置操作")


@pytest.mark.usefixtures("fixture_fun")
def test_001():
    print("我是用例1111111")

运行结果

============================= test session starts =============================
collecting ... collected 1 item

test_001.py::test_001 function级别的前置操作
PASSED                                             [100%]我是用例1111111
function级别的后置操作


============================== 1 passed in 0.01s ==============================

使用yield关键字实现后置操作

示列代码:

class Test001():
    @pytest.fixture(scope='function')
    def beferFunction(self):
        print("fixture的function前置操作")
        yield
        print("fixture的function后置操作")

    def test_001(self,beferFunction):
        print("测试用例001")

运行结果:

============================= test session starts =============================
collecting ... collected 1 item

test_002.py::Test001::test_001 fixture的function前置操作
PASSED                                    [100%]测试用例001
fixture的function后置操作


============================== 1 passed in 0.01s ==============================

其他级别前后置操作同理。

1、如果希望某个测试类下所有的方法都执行function级别的前后置方法,在测试类前使用@pytest.fixture(scope=‘function’)即可。

2、有多个同类型的scope叠加使用,从下至上依次执行。

(2)fixture数据传递

# 传递
yield 返回值
# 接收
# 以fixture函数名作为用例参数,用例参数接收返回值,可以有多个

示列代码:

import pytest


@pytest.fixture(scope="function")
def func01():
    print("函数级别的前置")
    yield "返回值1",100
    print("函数级别的后置")

@pytest.mark.usefixtures("func01")
def test001(func01): # 参数 func01 = 函数名叫做func01的返回值
    print(f"测试用例test001,接收到的参数为:{func01}") 

运行结果

============================= test session starts =============================
collecting ... collected 1 item

test_fixture前置数据传递.py::test001 函数级别的前置
PASSED                              [100%]测试用例test001,接收到的参数为:('返回值1', 100)
函数级别的后置


============================== 1 passed in 0.06s ==============================

(3)fixture全局共享机制conftest.py

  • 通过conftest.py文件实现共享fixture,文件名固定为conftest.py,不可更改

  • 用处:在不同的py文件中使用同一个fixture函数

  • 优先级:就近原则!

  • 共享范围:当前conftest.py所在目录下的所有用例共享,包括子文件夹

  • conftest.py,是可以创建多个在不同的包下,可以层级创建的。

  • conftest.py需要和运行的用例放到同一层,不需要用import导入操作

  • 所有同目录测试文件运行前都会执行conftest.py文件

新建如下目录结构:

【python自动化】pytest系列(下)_第2张图片

conftest.py文件中编写如下代码:

# -*- coding: utf-8 -*-
'''
@Time : 2023/2/15 11:51
@Author : Vincent.xiaozai
@Email : [email protected]
@File : conftest.py
'''
__author__ = "梦无矶小仔"

'''
1、放的都是fixture
2、fixture可以对外共享
3、共享范围:
    当前conftest.py所在目录下的所有用例共享,包括子文件夹
4、conftest.py,是可以创建多个在不同的包下,可以层级创建的。
5、优先级:就近原则!
'''

import pytest

@pytest.fixture(scope="function")
def func_fixture():
    print("conftest.py下的func_fixture前置")
    yield
    print("conftest.py下的func_fixture后置")
    
@pytest.fixture(scope="function")
def func_fixture_01():
    print("conftest.py下的func_fixture前置")
    yield
    print("conftest.py下的func_fixture后置")

@pytest.fixture(scope="class")
def class_fixture():
    print("conftest.py下的class_fixture前置")
    yield
    print("conftest.py下的class_fixture后置")

@pytest.fixture(scope="module")
def module_fixture():
    print("conftest.py下的module_fixture前置")
    yield
    print("conftest.py下的module_fixture后置")


@pytest.fixture(scope="function")
def func_fixture_param():
    print("conftest.py下的func_fixture_param前置")
    yield 1, 2, 3, 4, 5
    print("conftest.py下的func_fixture_param后置")

test_002.py文件中直接使用conftest.py文件中定义的fixture方法。

import pytest

@pytest.fixture(scope="function")
def func_fixture():
    print("test_002.py下的func_fixture前置")
    yield
    print("test_002.py下的func_fixture后置")

class Test002():

    def test_aa(self,func_fixture):
        print("----运行了test_aa用例----")

    def test_bb(self,func_fixture_01):
        print("----运行了test_bb用例----")

    def test_cc(self,class_fixture):
        print("----运行了test_cc用例----")

    def test_dd(self,func_fixture_param):
        print(f"----运行了test_dd用例----参数:{func_fixture_param}")

    @pytest.mark.usefixtures("func_fixture")
    def test_ee(self):
        print("----运行了test_ee用例----")

运行结果:

============================= test session starts =============================
collecting ... collected 5 items

test_002.py::Test002::test_aa test_002.py下的func_fixture前置
PASSED                                     [ 20%]----运行了test_aa用例----
test_002.py下的func_fixture后置

test_002.py::Test002::test_bb conftest.py下的func_fixture前置
PASSED                                     [ 40%]----运行了test_bb用例----
conftest.py下的func_fixture后置

test_002.py::Test002::test_cc conftest.py下的class_fixture前置
PASSED                                     [ 60%]----运行了test_cc用例----

test_002.py::Test002::test_dd conftest.py下的func_fixture_param前置
PASSED                                     [ 80%]----运行了test_dd用例----参数:(1, 2, 3, 4, 5)
conftest.py下的func_fixture_param后置

test_002.py::Test002::test_ee test_002.py下的func_fixture前置
PASSED                                     [100%]----运行了test_ee用例----
test_002.py下的func_fixture后置
conftest.py下的class_fixture后置


============================== 5 passed in 0.02s ==============================

我们在两个文件中都有func_fixture的fixture方法,运行发现,test_002.py使用的是自己文件下的,而不是conftest里面的,这很好的说明了一个就近原则。

(4)fixture嵌套

@pytest.fixture
def func1():
    print("func1的前置")
    yield
    print("func1的后置")

我有个需求,就是需要用到func1,但是我要在此基础上新增一些内容。于是乎我造了一个func2

@pytest.fixture
def func2():
    print("fun1的前置")
    print("新增:func2的前置")
    yield
    print("新增:func2的后置")
    print("func1的后置")

这样写会造成大量的代码冗余,有什么办法解决呢?这就需要用到我们继承的理念。

继承func1并在内部执行func1

@pytest.fixture
def func3(func1):
    print("新增:func3的前置")
    yield func1
    print("新增:func3的后置")

运行如下测试用例,输出结果就和调用func2运行一致。

def test001(func3):
    print("我是测试用例001")
    
    ### 运行结果如下 ###
============================= test session starts =============================
collecting ... collected 1 item

test_003_fixture嵌套.py::test001 func1的前置
新增:func3的前置
PASSED                                  [100%]我是测试用例001
新增:func3的后置
func1的后置


============================== 1 passed in 0.01s ==============================

Process finished with exit code 0

你可能感兴趣的:(python,自动化,pytest)