python测试框架之pytest (四)fixture

一 引言
在测试过程中,通常会包括三个步骤,前置、执行测试、后置,pytest框架中,提供了类似的函数。

模块级别:setup_module (前置) / teardown_module(后置) ->不在类中,全局的

函数级别:setup_function(前置)/ teardown_function(后置) ->不在类中

类级别: setup_class (前置) / teardown_class (后置) ->只在类中前后运行一次

方法级别:setup_method(前置)/ teardown_method (后置)->类中方法前后

用例级别:setup (前置)/ teardown (后置)->运行测试用例的前后

但是,这种前置、后置处理方式存在一定的缺陷。假如,一个测试类中,存在多个测试方法,每一个测试方法需要不同的前置、后置,该怎么处理会比较好呢?

pytest提供了一种高级的功能,fixture。可以通过实现文件共享机制,供模块、函数、类或者整个项目会话使用。

在conftest.py中实现文件共享机制,而且不需要import导入,pytest会自动去加载匹配对应的fixture。

二 fixture参数详解

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

1、scope:控制fixture作用域,默认是function级别

 session:每次会话只需要运行一次,会话内所有模块、类、方法,都共享这个fixture

 module:每一个.py文件调用一次

 class:每一个类中调用一次

 function:每一个function或者类方法中都会调用

2、params:可选的参数列表

 ①Fixture可选的参数列表,支持列表传入

 ②默认为None,每个param的值。

 ③可通过request.param接受设置的返回值,params中有多少个元素,在测试时,引用次fixture的函数就会调用几次。

 ④可与参数ids一起使用,作为每个参数的标识。

3、autouse:是否自动执行设置的fixture,默认是False

 当autouse为True时,自动执行定义的fixture。

 当autouse为False时,测试函数需要调用定义的fixture,定义的fixture函数才能执行。

4、ids:指定每个字符串id

 当有多个params时,针对每一个param,可以指定id,这个id将变成测试用例名字的一部分。如果没有提供id,id将自动生成。

5、name:fixture的重命名

 默认是fixture函数的名称,可以通过name参数更改这个fixture的名称。更改后,如果这个fixture被调用,则使用更改后的名称。

三 fixture应用
3.1、函数名调用fixture

import pytest


@pytest.fixture
def fix_a():
    print("调用fix_a")


def test_a(fix_a):
    print("执行test_a用例")

执行结果python测试框架之pytest (四)fixture
根据运行结果可以看出,先执行了前置fixture,再执行测试用例。

3.2、@pytest.mark.usefixtures调用fixture

import pytest


@pytest.fixture
def fix_a():
    print("调用fix_a")


@pytest.mark.usefixtures('fix_a')
def test_a1(fix_a):
    print("执行test_a1用例")

3.3、多参数调用fixture

@pytest.fixture(params=['a', 'b', 'c'], scope="function")
def fix_a2(request):
    print(f'调用fixture:{request.param}')


def test_a2(fix_a2):
    print('执行test_a2用例')

执行结果python测试框架之pytest (四)fixture
从执行结果,可以看到生成了三条测试用例,所以fixture也支持参数化。

3.4、autouse使用
从上面例子来看,fixture都需要主动调用,才能生效。但有时需要让用例自动执行,这时候就需要添加autouse参数,让fixture自动执行。

@pytest.fixture(autouse=True)
def fix_a3(request):
    case_name = request.node.name
    print(f"开始执行{case_name}测试用例 ")
    yield
    print(f"{case_name}测试用例执行结束 ")


def test_a3():
    print('test_a3')
    assert "tom" == "tom"

执行结果
python测试框架之pytest (四)fixture
从执行结果看,设置了autouse=True后,定义的fixture自动执行。并且定义的fixture通过yield关键字隔离前置、后置,yield之前是前置,yield之后是后置。

3.5、fixture嵌套使用

@pytest.fixture()
def fix_a4():
    print('调用fix_a4')


@pytest.fixture()
def fix_a5(fix_a4):
    print('调用fix_a5')


def test_a4(fix_a5):
    print('-----执行test_a4测试用例------')

执行结果
python测试框架之pytest (四)fixture
从执行结果看,调用fix_a5时,先调用fix_a4,再调用fix_a5。这个场景比较适用于多个测试场景组合,多个前置测试步骤时使用。

3.6、conftest.py共享机制
实际测试工作中,常需要在全局范围内使用同一个测试前置、后置操作。可以使用conftest.py,在conftest.py定义的fixture不需要进行import,pytest会自动查找使用。

3.7、有返回值的fixture

@pytest.fixture()
def fix_a6():
    amount = round(32.567, 2)
    yield amount


def test_a6(fix_a6):
    # 通过一个变量接收fix_a6
    amount = fix_a6
    print(f'fix_a6接受到的数据时{amount}')

执行结果
python测试框架之pytest (四)fixture
3.8、@pytest.fixture与@pytest.mark.parametrize结合使用

@pytest.fixture()
def fix_a7(request):
    print("fixture拿到的原始参数是:", request.param)
    sum = request.param[0] + request.param[1]
    yield sum


@pytest.mark.parametrize("fix_a7", [(1, 3), (2, 4)], indirect=True)
def test_a7(fix_a7):
    print('-----执行test_a7测试用例------')
    print(f"fixture返回的参数和是:{fix_a7}")

执行结果
python测试框架之pytest (四)fixture
首先,fixture做了参数化,需要在fixture中接受变量,传入request这个内置fixture。然后传入的变量,通过request的param接收,在@pytest.mark.parametrize中,将定义的xi_a7传入参数化中用例中。

上一篇:Pytest生成html测试报告


下一篇:f2pool E池 低延迟 稳定 解决连接失败