当前位置:   article > 正文

关于Pytest fixture,我们了解多少?

关于Pytest fixture,我们了解多少?

在这里插入图片描述

关于Pytest fixtures,根据官方文档介绍:fixture用于提供一个固定的基线,使 Cases 可以在此基础上可靠地、重复地执行。

对比 PyUnit 经典的setup/teardown形式,它在以下方面有了明显的改进:
fixture拥有一个明确的名称,通过声明使其能够在函数、类、模块,甚至整个测试会话中被激活使用;

fixture以一种模块化的方式实现,原因在于每一个fixture的名字都能触发一个fixture函数,而这个函数本身又能调用其它的fixture;

fixture的管理从简单的单元测试扩展到复杂的功能测试,允许通过配置和组件选项参数化fixture和测试用例,或者跨功能、类、模块,甚至整个测试会话复用fixture。

一句话概括:在整个测试执行的上下文中,fixture扮演注入者(injector)的角色,而测试用例扮演消费者(client)的角色,测试用例可以轻松的接收和处理需要预初始化操作的应用对象,而不用过分关心其实现的具体细节。

fixture的实例化顺序

fixture支持的作用域(Scope):function(default)、class、module、package、session。

其中,package作用域是在 pytest 3.7 的版本中,正式引入的,目前仍处于实验性阶段。

多个fixture的实例化顺序,遵循以下原则:

高级别作用域的(例如:session)优先于 低级别的作用域的(例如:class或者function)实例化;

相同级别作用域的,其实例化顺序遵循它们在测试用例中被声明的顺序(也就是形参的顺序),或者fixture之间的相互调用关系;

指明autouse=True的fixture,先于其同级别的其它fixture实例化。

fixture实现teardown功能

有以下几种方法(注意:在yield之前或者addfinalizer注册之前代码发生错误退出的,都不会再执行后续的清理操作):

将fixture变为生成器方法(推荐)

即将fixture函数中的return关键字替换成yield,则yield之后的代码,就是我们要的清理操作。

@pytest.fixture(scope='session', autouse=True)
def clear_token():
    yield
    from libs.redis_m import RedisManager
    rdm = RedisManager()
    rdm.expire_token(seconds=60)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用addfinalizer方法

fixture函数能够接收一个request的参数,表示测试请求的上下文(下面会详细介绍),我们可以使用request.addfinalizer方法为fixture添加清理函数。

@pytest.fixture()
def smtp_connection_fin(request):
    smtp_connection = smtplib.SMTP("smtp.163.com", 25, timeout=5)


    def fin():
        smtp_connection.close()


    request.addfinalizer(fin)
    return smtp_connection
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用with写法(不推荐)

对于支持with写法的对象,我们也可以隐式的执行它的清理操作:

@pytest.fixture()
def smtp_connection_yield():
    with smtplib.SMTP("smtp.163.com", 25, timeout=5) as smtp_connection:
        yield smtp_connection
  • 1
  • 2
  • 3
  • 4

fixture可以访问测试请求的上下文

fixture函数可以接收一个request的参数,表示测试用例、类、模块,甚至测试会话的上下文环境,例如可以扩展下上面的smtp_connection_yield,让其根据不同的测试模块使用不同的服务器:

@pytest.fixture(scope='module')
def smtp_connection_request(request):
    server, port = getattr(request.module, 'smtp_server', ("smtp.163.com", 25))
    with smtplib.SMTP(server, port, timeout=5) as smtp_connection:
        yield smtp_connection
        print("断开 %s:%d" % (server, port))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在测试模块中指定smtp_server:

smtp_server = ("mail.python.org", 587)
def test_163(smtp_connection_request):
    response, _ = smtp_connection_request.ehlo()
    assert response == 250
  • 1
  • 2
  • 3
  • 4

fixture返回工厂函数

如果需要在一个测试用例(function)中,多次使用同一个fixture实例,相对于直接返回数据,更好的方法是返回一个产生数据的工厂函数。并且,对于工厂函数产生的数据,也可以在fixture中对其管理:

@pytest.fixture
def make_customer_record():


    # 记录生产的数据
    created_records = []


    # 工厂
    def _make_customer_record(name):
        record = models.Customer(name=name, orders=[])
        created_records.append(record)
        return record


    yield _make_customer_record


    # 销毁数据
    for record in created_records:
        record.destroy()




def test_customer_records(make_customer_record):
    customer_1 = make_customer_record("Lisa")
    customer_2 = make_customer_record("Mike")
    customer_3 = make_customer_record("Meredith")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

fixture的参数化

如果你需要在一系列的测试用例的执行中,每轮执行都使用同一个fixture,但是有不同的依赖场景,那么可以考虑对fixture进行参数化,这种方式适用于对多场景的功能模块进行详尽的测试。

@pytest.fixture(scope='module', params=['smtp.163.com', "mail.python.org"])
def smtp_connection_params(request):
    server = request.param
    with smtplib.SMTP(server, 587, timeout=5) as smtp_connection:
        yield smtp_connection


def test_parames(smtp_connection_params):
    response, _ = smtp_connection_params.ehlo()
    assert response == 250
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在不同的层级上覆写fixture

注意:低级别的作用域可以调用高级别的作用域,但是高级别的作用域调用低级别的作用域会返回一个ScopeMismatch的异常。

在大型的测试中,可能需要在本地覆盖项目级别的fixture,以增加可读性和便于维护:

@pytest.fixture(scope="module", autouse=True)
def init(frag_login):
    pass


@pytest.fixture(scope='session')
def active_user_account(cmd_line_args, conf):
    tail_num = cmd_line_args.get("tailnum", None)
    if tail_num is None:
        tail_num = "1"
    for user in conf['unified']:
        if str(user['uid'])[-1] == tail_num:
            return user
    msg = f"尾号[{tail_num}], 在配置文件中未找到"
    logger.error(msg)
    raise ValueError(msg)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取 【保证100%免费】

在这里插入图片描述

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/764576
推荐阅读
相关标签
  

闽ICP备14008679号