python + pytest 之 fixture装饰器使用详解

发布时间 2023-05-09 04:33:16作者: 乌鸦哥

简介:

  fixture装饰器区别于unnitest的传统单元测试(setup/teardown)有显著改进:

  1.fixture装饰的函数可独立命名,并通过声明范围scope,可从测试函数、模块、类或整个项目来使用。

  2.按模块化的方式实现,每个fixture都可以互相调用。

  3.fixture的范围从简单的单元测试到复杂的功能测试,可以对fixture配置参数,或者跨函数function,类class,模块module或整个测试session范围。

 

 fixture装饰的函数可以当做参数传入

定义fixture的函数跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture函数命名不需要以test开头,可以跟用例区分开。fixture是有返回值得,没有返回值默认为None。用例调用fixture函数的返回值,直接就是把fixture的函数名当做变量名。 

# @File: test_fixture.py
import pytest
@pytest.fixture()
def test_01():
    a = 10
    print('test_01被调用了...')
    return a

def test_02(test_01):
    assert test_01 == 10
    print("断言成功")

def test_03(test_01):
    assert test_01 == 10
    print("断言成功")

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

============================= test session starts =============================
platform win32 -- Python 3.8.5, pytest-5.4.2, py-1.11.0, pluggy-0.13.1
rootdir: D:\PycharmProjects\apiFrame_gnh_230313\common
plugins: allure-pytest-2.8.6, assume-2.4.3
collected 2 items

test_fixture.py test_01被调用了...
断言成功
.test_01被调用了...
断言成功
.

============================== 2 passed in 0.03s ==============================

   

fixture返回多个值(元组、列表等)

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

# @File: test_fixture2.py
import pytest
@pytest.fixture(scope='function') # scope='function' 为默认值
def test_01():
    a = 8
    b = 9
    return (a, b)

def test_02(test_01):
    a = test_01[0]
    b = test_01[1]
    assert a < b
    print("断言成功")

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

============================= test session starts =============================
platform win32 -- Python 3.8.5, pytest-5.4.2, py-1.11.0, pluggy-0.13.1
rootdir: D:\PycharmProjects\apiFrame_gnh_230313\common
plugins: allure-pytest-2.8.6, assume-2.4.3
collected 1 item

test_fixture2.py 断言成功
.

============================== 1 passed in 0.05s ==============================

 

fixture的作用范围(scope)

fixture里面有个scope参数可以控制fixture的作用范围:function < class < module < session

-function:每个函数或方法都可以调用。scope='function' 为默认值。

-class:每个类仅调用一次,一个类中可以有多个方法

-module:每个.py文件仅调用一次,该文件内又可以有多个function和class

-session:多个文件仅调用一次,可以跨.py文件调用,每个.py文件就是模块module


# @File: test_fixture3.py
import pytest
@pytest.fixture(scope="class")
def test_01():
    a = 8
    b = 9
    print('test_01被调用了...')
    return (a, b)

class TestDemo:
    def test_02(self, test_01):
        a = test_01[0]
        b = test_01[1]
        assert a < b
        print("断言成功")

    def test_03(self, test_01):
        a = test_01[0]
        b = test_01[1]
        assert a < b
        print("断言成功")
        
if __name__=='__main__':
    pytest.main(['-s', 'test_fixture3.py'])

============================= test session starts =============================
platform win32 -- Python 3.8.5, pytest-5.4.2, py-1.11.0, pluggy-0.13.1
rootdir: D:\PycharmProjects\apiFrame_gnh_230313\common
plugins: allure-pytest-2.8.6, assume-2.4.3
collected 2 items

test_fixture3.py test_01被调用了...
断言成功
.断言成功
.

============================== 2 passed in 0.04s ==============================

 

调用fixture的三种方法

1.函数或方法的参数列表中直接传fixture的函数名

PS:代码详见上图

2.使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例


# @File: test_fixture4.py
import pytest
@pytest.fixture(scope="class")
def test_01():
    a = 8
    b = 9
    print('test_01被调用了...')
    return (a, b)

@pytest.mark.usefixtures("test_01") # 默认有的装饰器
class TestDemo:
    def test_02(self,test_01):
        a = test_01[0]
        b = test_01[1]
        assert a < b
        print("断言成功")

    def test_03(self,test_01):
        a = test_01[0]
        b = test_01[1]
        assert a < b
        print("断言成功")
        
if __name__=='__main__':
    pytest.main(['-s', 'test_fixture4.py'])

============================= test session starts =============================
platform win32 -- Python 3.8.5, pytest-5.4.2, py-1.11.0, pluggy-0.13.1
rootdir: D:\PycharmProjects\apiFrame_gnh_230313\common
plugins: allure-pytest-2.8.6, assume-2.4.3
collected 2 items

test_fixture4.py test_01被调用了...
断言成功
.断言成功
.

============================== 2 passed in 0.05s ==============================

3.叠加使用多个usefixtures

 如果一个方法或者一个class用例想要同时调用多个fixture,可以使用@pytest.mark.usefixture()进行叠加。注意叠加顺序,先执行的放底层,后执行的放上层。

# @File: test_fixture5.py
import pytest
@pytest.fixture(scope="class")
def test_01():
    a = 8
    b = 9
    print('test_01被调用了...')
    return (a, b)

@pytest.fixture(scope="class")
def test_02():
    print("test_02被调用了...")
    return 'hello123'

@pytest.mark.usefixtures("test_01")
@pytest.mark.usefixtures("test_02") # 底层的优先执行
class TestDemo:
    def test_03(self,test_01,test_02):
        a = test_01[0]
        b = test_01[1]
        print(test_02)
        assert a < b
        print("断言成功")

    def test_04(self,test_02):
        print(test_02)

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

============================= test session starts =============================
platform win32 -- Python 3.8.5, pytest-5.4.2, py-1.11.0, pluggy-0.13.1
rootdir: D:\PycharmProjects\apiFrame_gnh_230313\common
plugins: allure-pytest-2.8.6, assume-2.4.3
collected 2 items

test_fixture5.py test_02被调用了...
test_01被调用了...
hello123
断言成功
.hello123
.

============================== 2 passed in 0.04s ==============================