pytest fixture

pytest fixture

1. 通过conftest.py 共享fixture

@pytest.fixture()装饰器用于声明函数是一个fixture,如果测试用例的参数列表中包含fixture, pytest会优先搜索该测试用例所在的模块,然后搜索conftest.py文件。
conftest.py中的fixture可以供其所在目录及其子目录下的测试案例使用,并且conftest.py 文件不能被导入

2. 使用fixture执行配置及销毁逻辑

import pytest                    

@pytest.fixture(scope='module')  
def get_data():                  
    print('fixture start')       
    yield 44                     
    print('fixture end')         
                                 
                                 
def test_add(get_data):          
    print(123)                   
    print(get_data)              
                                 
                                 
def test_add2(get_data):         
    print(1234)                  
    print(get_data)              
                                 
                                 
def test_add3(get_data):         
    print(456)                   
    print(get_data)              

fixture 函数会在测试函数之前运行,但如果fixture函数包含yield,那么系统会在yield处停止,转而运行测试函数,等测试函数执行完毕后再回到fixture,继续执行yield后面的代码。因此可以将yield 之前的代码视为配置(setup)的过程,将yield之后的代码视为清理(teardown)的过程,无论测试过程中发生了什么,yield之后的代码都会被执行。所以yield 可以用作测试案例的前置条件。

I:\APIAutoTest>pytest -v --setup-show test.py
================================================================================================================================================== test session starts ===================================================================================================================================================
platform win32 -- Python 3.9.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- d:~\python39\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.9.5', 'Platform': 'Windows-10-10.0.19042-SP0', 'Packages': {'pytest': '6.2.4', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'allure-pytest': '2.9.43', 'html': '3.1.1', 'metadata': '1.11.0'}}
rootdir: I:\APIAutoTest
plugins: allure-pytest-2.9.43, html-3.1.1, metadata-1.11.0
collected 3 items                                                                                                                                                                                                                                         
test11.py::test_add
    SETUP    M get_data
        test11.py::test_add (fixtures used: get_data)PASSED。 
test11.py::test_add2
        test11.py::test_add2 (fixtures used: get_data)PASSED
test11.py::test_add3
        test11.py::test_add3 (fixtures used: get_data)PASSED
    TEARDOWN M get_data

运行结果如上,
pytest 提供命令--setup-show可以看到测试过程中执行的顺序是什么,以及执行的先后顺序, setup后面的M表示的事fixture的作用范围

3. 使用fixture传递测试数据

fixture非常适合存放测试数据,并且它可以返回任何测试数据.
如果测试结果为Fail,用户就知道失败是发生在核心测试函数内,测试结果是Error,就知道失败是发生在测试依赖的Fixture。
如下:

import pytest         

#异常发生在测试函数内,测试结果为Fail                                                  
@pytest.fixture(scope='module')       
def get_data():                       
    print('fixture start')            
    yield 44                          
    print('fixture end')              
                                      
                                      
def test_add(get_data):               
    get_data + 'a' 
    print(get_data)                    

================================================== FAILURES===============================================
_______________________________________________ test_add__________________________________________________

get_data = 44

    def test_add(get_data):
>       get_data + 'a'
E       TypeError: unsupported operand type(s) for +: 'int' and 'str'


import pytest                     
                                  
# 异常发生在fixture内,测试结果为Error                               
@pytest.fixture(scope='module')   
def get_data():                   
    print('fixture start')        
    yield 44 + 'a'                
    print('fixture end')          
                                  
                                  
def test_add(get_data):           
    print(get_data)               



================================== ERRORS ========================================
_______________________ ERROR at setup of test_add _______________________________

    @pytest.fixture(scope='module')
    def get_data():
        print('fixture start')
>       yield 44 + 'a'
E       TypeError: unsupported operand type(s) for +: 'int' and 'str'

4. 指定fixture的作用范围

测试函数中可以使用多个fixture。

test_1:
        /__init__.py
        /contfest.py
        /test_1.py
        /test2:
                /conftest.py
                /test_2.py

如果test_1文件夹下的conftest.py和test_2文件夹下的conftest.py中都有fixture,那test_2.py中都可以使用这二个文件夹中的fixture

@pytest.fixture的scope参数有四个待选值,分别是function,class,module,package,session

官方文档解释如下:
https://docs.pytest.org/en/latest/how-to/fixtures.html#scope-sharing-fixtures-across-classes-modules-packages-or-session

  • function: the default scope, the fixture is destroyed at the end of the test.

  • class: the fixture is destroyed during teardown of the last test in the class.

  • module: the fixture is destroyed during teardown of the last test in the module.

  • package: the fixture is destroyed during teardown of the last test in the package.

  • session: the fixture is destroyed at the end of the test session.

function级别的fixture,每个测试函数都会运行fixture(都会setup和teardown)function是scope的默认值

class级别的fixture,每个测试类运行一次fixture,,无论测试类里面有多少个类方法,都可以共享这个fixture,运行完类的所有测试函数后会销毁fixture。 比如一个py文件里面与三个类,fixture的级别是class,那会调用三次fixture

module级别的fixture,运行完一个py文件后,销毁fixture,也就是说运行一个py文件,运行一次fixture。

package 级别的fixture,运行完文件下的所有测试的py文件之后,销毁fixture,
session级别的fixture,测试完成后才会销毁fixture
fixture只能使用同级别的fixture,或者比自己更高级别的fixture,比如函数级别的fixture可以使用函数级别的fixture,也可以使用module级别的fixture。
在定义fixture的时候,将参数autouse设置为True时,则在执行用例的时候自动去加载,无需显示调用

5. fixture的重命名

import sys
import pytest
@pytest.fixture(scope='class', name='test')
def test_fixture_test_20210109():
    print('fixture start')
    yield 44
    print('fixture end')

class TestA:

    def test_a1(self, test):
        print('{} call'.format(sys._getframe().f_code.co_name))

6. fixture的参数化

fixture 参数化和参数化测试相比,对测试函数的参数可以pre-excute

import pytest

def id_func(b):
    return 'id is {}'.format(b)

num = [4, 2, 3]
@pytest.fixture(params=num, ids=id_func, scope='function')
def get_num(request):
    print('get num {}'.format(request.param))
    request.param += 1  # 对即将要传入测试函数的参数进行统一的pre-excute
    return request.param

# ids参数可以指定为一个函数,供测试函数生成标识

def test_1(get_num):
    print(get_num)

def test_2(get_num):
    print(get_num)


userkeylist = [4, 2, 3]
@pytest.mark.parametrize('userkey', userkeylist)
def test_user(userkey):
    # 在测试函数中,对参数进行操作
    userkey += 1
    print(userkey)

运行结果如下:

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

test_A2.py::test_1[id is 4] get num 4
PASSED                                       [ 12%]5

test_A2.py::test_1[id is 2] get num 2
PASSED                                       [ 25%]3

test_A2.py::test_1[id is 3] get num 3
PASSED                                       [ 37%]4

test_A2.py::test_2[id is 4] get num 4
PASSED                                       [ 50%]5

test_A2.py::test_2[id is 2] get num 2
PASSED                                       [ 62%]3

test_A2.py::test_2[id is 3] get num 3
PASSED                                       [ 75%]4

test_A2.py::test_user[4] PASSED                                          [ 33%]5

test_A2.py::test_user[2] PASSED                                          [ 66%]3

test_A2.py::test_user[3] PASSED                                          [100%]4
posted @   焰红火  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示