Pytest 的 fixture 函数

Posted on Wed, 25 Dec 2024 16:08:06 +0800 by LiangMingJian


概述

fixture 是 pytest 提供给测试环境初始化与清理的一个函数,通过语法糖 @pytest.fixture(),测试用例会在测试开始前与测试结束后自动执行带有标记的函数,完成测试环境的初始化与清理。

fixture 的优势有:

  • 能独立的命名,并且能通过声明从测试函数、模块、类中使用;
  • 按模块化的方式实现,每个 fixture 都可以互相调用;
  • fixture 跨函数 function,类 class,模块 module 或整个测试 session 使用;

fixture 的作用范围

fixture 里通过 scope 参数控制 fixture 的作用范围。

  • function:每一个函数或方法都会调用
  • class:每一个类调用一次,一个类中可以有多个方法
  • module:每一个 .py 文件调用一次,该文件内又有多个 function 和 class
  • session:是多个文件调用一次,可以跨 .py 文件调用,每个 .py 文件就是 module

支持的参数

fixture(scope='function', params=None, autouse=False, ids=None, name=None)
  • scope:有四个级别参数"function"(默认),“class”,“module”,“session”
  • params:一个可选的参数列表。
  • autouse:如果 True,则为所有测试都可以自动使用 fixture 函数。如果为 False 则显示需要传参来激活 fixture
  • ids:每个字符串 id 的列表,每个字符串对应于 params 这样他们就是测试 ID 的一部分。如果没有提供 ID 它们将从 params 自动生成
  • name:fixture 的名称。这默认为装饰函数的名称。

直接传递 fixture 函数名来调用

@pytest.fixture()
def test1():
    print('\n开始执行function')

def test_a(test1):
    print('---用例a执行---')

class TestCase:
    def test_b(self, test1):
        print('---用例b执行')

使用装饰器来调用

@pytest.fixture()
def test1():
    print('\n开始执行function')

@pytest.mark.usefixtures('test1')
def test_a():
    print('---用例a执行---')

@pytest.mark.usefixtures('test1')
class TestCase:
    def test_b(self):
        print('---用例b执行---')
    def test_c(self):
        print('---用例c执行---')

# 调用多个fixture,叠加usefixtures
@pytest.mark.usefixtures('test1')
@pytest.mark.usefixtures('test2')
def test_a():
    print('---用例a执行---')

# 如果fixture有返回值,那么usefixture就无法获取到返回值,这个是装饰器usefixture与用例直接传fixture参数的区别。
# 当fixture需要用到return出来的参数时,只能讲参数名称直接当参数传入,不需要用到return出来的参数时,两种方式都可以。

设置为自动使用

当用例很多的时候,每次都传这个参数,会很麻烦。fixture 里面有个参数 autouse,默认是 False 没开启的,可以设置为 True 开启自动使用 fixture 功能,这样用例就不用每次都去传参了。将 autouse 设置为 True,自动调用 fixture 功能。

@pytest.fixture(scope='module', autouse=True)
def test1():
    print('\n开始执行module')

示例一:基本使用

fixture(scope="function", params=None, autouse=False, ids=None, name=None)
# scope:被标记方法的作用域 
"function": 默认值, 作用于每个测试方法, 每个test都运行一次
"class": 作用于整个类, 每个class的所有test只运行一次
"module": 作用于整个模块, 每个module的所有test只运行一次
"session": 作用于整个session(慎用), 每个session只运行一次
# params:(list类型)提供参数数据,供调用标记方法的函数使用
# autouse:是否自动运行,默认为False不运行,设置为True自动运行
# 使用----------------------------------------------------------------------
@pytest.fixture()
def before(self):
    pass
def test_a(self,before): # ️test_a方法传入了被fixture标识的函数,已变量的形式
    pass
# 使用----------------------------------------------------------------------
def before():
    pass
@pytest.mark.usefixtures("before")
class Test_ABC:
    def setup(self):
        pass
    def test_a(self):
        pass
# 使用----------------------------------------------------------------------
@pytest.fixture()
def need_data():
    return 2 # 返回数字2
class Test_ABC:
    def test_a(self,need_data):
        assert need_data != 3 # 拿到返回值做一次断言

示例二:fixture 当做参数传入

定义 fixture 跟定义普通函数差不多,唯一区别就是在函数上加个装饰器 @pytest.fixture(),fixture 命名不要以 test 开头,跟用例区分开。

fixture 是有返回值得,没有返回值默认为 None。用例调用 fixture 的返回值,直接就是把fixture 的函数名称当做变量名称。

@pytest.fixture()
def K():
    a = 'leo'
    return a
def test2(K):
    assert test1 == 'leo'

示例三:使用多个 fixture

如果用例需要用到多个 fixture 的返回数据,fixture 也可以返回一个元祖,list 或字典,然后从里面取出对应数据。

@pytest.fixture()
def test1():
    a = 'leo'
    b = '123456'
    print('传出a,b')
    return (a, b)

def test2(test1):
    u = test1[0]
    p = test1[1]
    assert u == 'leo'
    assert p == '123456'
    print('元祖形式正确')