Pytest - Fixture(6) - 作用域混用/执行顺序/依赖关系

发布时间 2023-05-29 09:29:44作者: 粥雨

Pytest - Fixture作用域混用

  • 若测试用例调用多个不同级别的作用域,都会同时生效:

conftest.py

import pytest

"""会话级别fixture,作用域当前目录"""
@pytest.fixture(scope="session")
def login_session():
    """作用于整个py文件"""
    print("\n*** session级别的作用域前置操作 ***")
    yield
    print("*** session级别的作用域后置操作 ***")

test_py.py

import pytest

"""用例级别fixture,作用域单个用例"""
@pytest.fixture(scope="function")
def login_func():
    print("\n--- function级别的作用域前置操作 ---")
    yield
    print("--- function级别的作用域后置操作 ---")

    
"""类级别fixture,作用域整个类"""
@pytest.fixture(scope="class", autouse=True)
def login_cls():
    print("\n=== class级别的作用域前置操作 ===")
    yield
    print("=== class级别的作用域后置操作 ===")

    
"""模块级别fixture,作用域整个py文件"""
@pytest.fixture(scope="module")
def login_module():
    print("\n^^^ module级别的作用域前置操作 ^^^")
    yield
    print("^^^ module级别的作用域后置操作 ^^^")
    

def test_s2(login_session, login_module, login_cls, login_func):
    print("\n用例test_s2:在类外的测试用例")

class Test_cls():
    def test_s1(self, login_func, login_cls, login_module, login_session):
        print("\n用例test_s1:在类中的测试用例")

    def test_s3(self, login_func):
        print("\n用例test_s3:在类中的测试用例")

if __name__ == '__main__':
    pytest.main(['-s', 'test_py.py'])


从执行结果中可以看出(测试用例test_s1,test_s2),不管测试用例调用Fixture函数顺序如何,执行顺序均为(从左到右分别为:先执行 > 后执行):

session > module > class > function


  • 执行结果如图所示各级别作用域:
    • 黄色框: function
    • 紫色框: class
    • 蓝色框: module
    • 红色框: session

image-20220922120921976



作用域执行顺序

  • 如果有多个不同作用域的需要执行,要弄清楚它们将执行的顺序;

  • pytest首先执行范围更高的fixtrue;

    • 在请求fixture函数中,先执行较高作用域范围的fixture(session,package,module);

    • 再执行在较低作用域的fixture(class,function);

test_py.py

import pytest

@pytest.fixture
def func(scope="function"):
    print("Function")

@pytest.fixture(scope="class")
def cls():
    print("Class")

@pytest.fixture(scope="module")
def mod():
    print("Module")

@pytest.fixture(scope="package")
def pack():
    print("Package")

@pytest.fixture(scope="session")
def sess():
    print("\nSession")

class TestClass:
    # 将作用域的顺序打乱,查看执行结果
    def test_s1(self, cls, mod, sess, func, pack):
        print("\n测试用例")

if __name__ == "__main__":
    pytest.main("-s", "test_py.py")
  • 执行顺序结果如图,按照作用域的高至低的顺序为:

    • Seesion > Package > Module > Class > Function

    image-20230306152055734



作用域依赖关系

  • 添加了 @pytest.fixture ,如果fixture还想依赖其他fixture,需要用函数传参的方式:

    • 当一个函数请求另一个函数时,首先执行另一个函数。
    • 如果函数 b 请求函数 a,函数 a 将首先执行,因为 b依赖于 a ,没有 a 就无法运行。
    • 即使 b 不需要 a的结果 ,它仍然可以请求 a 是否需要,确保在之后执行 a

    test_py.py

    import pytest
    
    @pytest.fixture()
    def a():
        print("\n第一个Fixture:a")
    
    @pytest.fixture()
    def b(a):
        print("第二个Fixture:b")
    
    @pytest.fixture()
    def c(a, b):
        print("第三个Fixture:c")
    
    @pytest.fixture()
    def d(a):
        print("第四个Fixture:d")
    
    @pytest.fixture()
    def z(d, c):
        print("第五个Fixture:z")
    
    # 测试用例只调用 函数z
    def test_s1(z):
        print("\n用例test_s1:Fixture 相互调用")
    
    if __name__ == '__main__':
        pytest.main(['-s', 'test_py.py'])
    
  • 执行依赖关系结果如图:

    • 单个fixture被多个fixture调用,只会执行一次;例如函数a 被函数b、c、d调用,但只执行了一次;

    • 优先执行顺序靠前的fixture;例如def z(d, c):,优先执行函数 d

    • 优先执行最先被调用的fixture;例如上述,函数a 为最先被 函数 d 调用的,函数d 为最先被 函数 z 调用;

    image-20230306175754122