【pytest】fixture 间的互调,fixture 的作用域、执行顺序

fixtures 之间互调:

pytest 中 fixtures 之间也可以互相调用:

# conftest.py

import pytest


@pytest.fixture()
def fix_init_1():
    print(" \nfix_init_1...")


@pytest.fixture()
def fix_init_2(fix_init_1):
    print(" \nfix_init_2...")


@pytest.fixture()
def fix_init_3(fix_init_2):
    print(" \nfix_init_3...")
# test_moduleName.py

import pytest

class TestClassName:
    """测试类"""

    def test_func(self, fix_init_3):
        """测试方法"""

        pass
# 执行结果

============================= test session starts =============================
test_moduleName.py::TestClassName::test_func  
fix_init_1... 
fix_init_2... 
fix_init_3...PASSED

============================== 1 passed in 0.02s ==============================

fixture 的作用域:

@pytest.fixture() 可以用 scope 参数来指定其作用域:

例如:@pytest.fixture(scope='class')

注意:当 fixture 作用域为 function 时,且装饰在测试类上,那么这个测试类的每个方法都会调用执行一次这个 fixture;

  • function  :fixture 默认的作用域,每个测试方法执行一次(如果被调用),默认时可以不用指定;
  • class      :每个测试类执行一次,如果同一个测试类中多次调用该 fixture 也只会执行一次;
  • module   :每个测试模块执行一次,如果同一个测试模块多次调用该 fixture 也只会执行一次;
  • package :(可能淘汰,不建议使用)每个 package 中只执行一次,如果同一个 package 下多次调用,也只会执行一次;
  • session   :每次测试会话中只执行一次,在同一次会话中多次调用,也只会执行一次;

说明:当 fixture 有返回值时,pytest 会把返回值缓存起来,如果 fixture 在指定的作用域内被多次调用,只有第一次调用会真正的被执行,后续调用会使用被缓存起来的返回值,而不是再执行一遍;

# conftest.py

import pytest

# 作用域 function
@pytest.fixture(scope='function')
def fix_func():
    print('\n方法级:fix_func...')

# 作用域 class
@pytest.fixture(scope='class')
def fix_class():
    print('\n类级:fix_class...')

# 作用域 module
@pytest.fixture(scope='module')
def fix_module():
    print('\n模块级:fix_module...')

# 作用域 session
@pytest.fixture(scope='session')
def fix_session():
    print('\n会话级:fix_session...')

 我们在3个测试方法中同时调用了4个级别的 fixture:

# test_moduleName.py

import pytest

class TestClass_1:
    """测试类1"""

    @pytest.mark.usefixtures('fix_func')
    @pytest.mark.usefixtures('fix_class')
    @pytest.mark.usefixtures('fix_module')
    @pytest.mark.usefixtures('fix_session')
    def test_func_1(self):
        """测试方法1"""
        pass

    @pytest.mark.usefixtures('fix_func')
    @pytest.mark.usefixtures('fix_class')
    @pytest.mark.usefixtures('fix_module')
    @pytest.mark.usefixtures('fix_session')
    def test_func_2(self):
        """测试方法2"""
        pass

class TestClass_2:
    """测试类2"""

    @pytest.mark.usefixtures('fix_func')
    @pytest.mark.usefixtures('fix_class')
    @pytest.mark.usefixtures('fix_module')
    @pytest.mark.usefixtures('fix_session')
    def test_func_3(self):
        """测试方法3"""
        pass

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

 可以看到:

test_func_1 的调用全部被执行了;

test_func_2 的调用只有 function 级的被执行,因为 test_func_2 和 test_func_1 同属于同一个 session、module、class,所以这三个都不执行,只有 function 执行;

test_func_3 的调用执行了类级和方法级,因为 test_func_3 属于 另外一个类,所以 class 级会被再次调用;

# 执行结果:
============================= test session starts =============================
test_moduleName.py::TestClass_1::test_func_1 
会话级:fix_session...
模块级:fix_module...
类级:fix_class...
方法级:fix_func...
PASSED
test_moduleName.py::TestClass_1::test_func_2 
方法级:fix_func...
PASSED
test_moduleName.py::TestClass_2::test_func_3 
类级:fix_class...
方法级:fix_func...
PASSED

============================== 3 passed in 0.02s ==============================

Process finished with exit code 0

fixture 的执行顺序:

前面讲过,fixture 可以同时使用多个,且 fixture 间可以相互调用,那么当一个测试方法同时调用多个fixture时,会根据各fixture作用域、依赖关系、传参顺序来确定fixture的执行顺序; 

而且,执行顺序要分两种情况:

    一. 用例前置(yield 之前):

  1. 先按作用域,先执行作用域高的(先session级,最后执行function级);
  2. 再按依赖关系,在执行某个fixture时,如果它调用了其他的fixture那就先执行被调用的fixture;
  3. 再按传参顺序,在测试方法中如果f1的传参位置在f2的前面,那么就先执行f1,再执行f2;
  4. 如果是用装饰器的方法使用fixtures,那么下方的fixture先执行,上方的fixture后执行;
  5. 如果同时用了传参和装饰器的方法使用fixtures,那么先执行装饰器的fixture,再执行传参的fixture; 

    二. 用例后置(yield 之后):

  • 完全和前置的顺序相反,同一个 fixture 的前置越晚执行,后置就越早执行!
# conftest.py

import pytest

@pytest.fixture
def fix_func():
    print('\n方法级-被调用方...')
    yield
    print('\n方法级-被调用方...')

@pytest.fixture
def fix_func_param_1(fix_func):
    print('\n方法级-传参法-1...')
    yield
    print('\n方法级-传参法-1...')

@pytest.fixture
def fix_func_param_2():
    print('\n方法级-传参法-2...')
    yield
    print('\n方法级-传参法-2...')

@pytest.fixture
def fix_func_param_3():
    print('\n方法级-传参法-3...')
    yield
    print('\n方法级-传参法-3...')

@pytest.fixture
def fix_func_decorator_1(fix_func):
    print('\n方法级-装饰器-1...')
    yield
    print('\n方法级-装饰器-1...')

@pytest.fixture
def fix_func_decorator_2():
    print('\n方法级-装饰器-2...')
    yield
    print('\n方法级-装饰器-2...')

@pytest.fixture
def fix_func_decorator_3():
    print('\n方法级-装饰器-3...')
    yield
    print('\n方法级-装饰器-3...')

# 作用域 class
@pytest.fixture(scope='class')
def fix_class():
    print('\n类级:fix_class...')
    yield
    print('\n类级:fix_class...')

# 作用域 module
@pytest.fixture(scope='module')
def fix_module():
    print('\n模块级:fix_module...')
    yield
    print('\n模块级:fix_module...')

# 作用域 session
@pytest.fixture(scope='session')
def fix_session():
    print('\n会话级:fix_session...')
    yield
    print('\n会话级:fix_session...')
# test_moduleName.py

import pytest

class TestClass_1:
    """测试类1"""

    @pytest.mark.usefixtures('fix_class')
    @pytest.mark.usefixtures('fix_session')
    @pytest.mark.usefixtures('fix_func_decorator_3')
    @pytest.mark.usefixtures('fix_func_decorator_2')
    @pytest.mark.usefixtures('fix_func_decorator_1')
    def test_func(self, fix_func_param_1, fix_func_param_2, fix_func_param_3, fix_module):
        """测试方法"""

        print('==============>>>执行测试用例<<<==============')

if __name__ == '__main__':
    pytest.main(['-s'])
# 执行结果:
============================= test session starts =============================
test_moduleName.py::TestClass_1::test_func 
会话级:fix_session...
模块级:fix_module...
类级:fix_class...
方法级-被调用方...
方法级-装饰器-1...
方法级-装饰器-2...
方法级-装饰器-3...
方法级-传参法-1...
方法级-传参法-2...
方法级-传参法-3...
==============>>>执行测试用例<<<==============
PASSED
方法级-传参法-3...
方法级-传参法-2...
方法级-传参法-1...
方法级-装饰器-3...
方法级-装饰器-2...
方法级-装饰器-1...
方法级-被调用方...
类级:fix_class...
模块级:fix_module...
会话级:fix_session...

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

Process finished with exit code 0

fixture的 autouse 参数:

autouse 参数的作用是 自动执行,也就是说,这个 fixture 不用主动调用,它会在相应的作用域中自动执行,并且在同一作用域中优先级最高;

# conftest.py

import pytest

# 增加一个 fix_auto 夹具
@pytest.fixture(autouse=True)
def fix_auto():
    print('\n方法级-自动执行...')
    yield
    print('\n方法级-自动执行...')
# test_moduleName.py

import pytest


class TestClass_1:
    """测试类1"""

    @pytest.mark.usefixtures('fix_class')
    @pytest.mark.usefixtures('fix_session')
    @pytest.mark.usefixtures('fix_func_decorator_1')
    def test_func(self, fix_func_param_1, fix_module):
        """测试方法"""

        print('==============>>>执行测试用例<<<==============')
============================= test session starts =============================
test_moduleName.py::TestClass_1::test_func 
会话级:fix_session...
模块级:fix_module...
类级:fix_class...
方法级-自动执行...
方法级-被调用方...
方法级-装饰器-1...
方法级-传参法-1...
==============>>>执行测试用例<<<==============
PASSED
方法级-传参法-1...
方法级-装饰器-1...
方法级-被调用方...
方法级-自动执行...
类级:fix_class...
模块级:fix_module...
会话级:fix_session...
============================== 1 passed in 0.03s ==============================

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值