pytest fixture-作用域:class、module、package或session共享fixture

2022-03-18 14:07 更新

需要网络访问的​​fixture​​依赖于连接,通常需要花费大量的时间来创建。扩展前面的例子,我们可以给​​@pytest​​添加一个​​scope="module"​​参数。​​fixture​​调用​​smtp_connection fixture​​函数,该函数负责创建到先前存在的SMTP服务器的连接,每个测试模块只调用一次(默认情况下是每个测试函数调用一次)。因此,一个测试模块中的多个测试函数将接收相同的​​smtp_connection fixture​​实例,从而节省时间。作用域的可能值有:函数、类、模块、包或会话。

下一个示例将​​fixture ​​函数放入一个单独的​​conftest.py​​ 文件中,以便目录中多个测试模块的测试可以访问​​fixture​​函数:

# content of conftest.py
import pytest
import smtplib


@pytest.fixture(scope="module")
def smtp_connection():
    return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
# content of test_module.py


def test_ehlo(smtp_connection):
    response, msg = smtp_connection.ehlo()
    assert response == 250
    assert b"smtp.gmail.com" in msg
    assert 0  # for demo purposes


def test_noop(smtp_connection):
    response, msg = smtp_connection.noop()
    assert response == 250
    assert 0  # for demo purposes

在这里, ​​test_ehlo ​​需要 ​​smtp_connection fixture​​值。 ​pytest ​将发现并调用 ​​@pytest.fixture​​ 标记的 ​​smtp_connection fixture​​函数。 运行测试如下所示:

$ pytest test_module.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items

test_module.py FF                                                    [100%]

================================= FAILURES =================================
________________________________ test_ehlo _________________________________

smtp_connection = <smtplib.SMTP object at 0xdeadbeef0001>

    def test_ehlo(smtp_connection):
        response, msg = smtp_connection.ehlo()
        assert response == 250
        assert b"smtp.gmail.com" in msg
>       assert 0  # for demo purposes
E       assert 0

test_module.py:7: AssertionError
________________________________ test_noop _________________________________

smtp_connection = <smtplib.SMTP object at 0xdeadbeef0001>

    def test_noop(smtp_connection):
        response, msg = smtp_connection.noop()
        assert response == 250
>       assert 0  # for demo purposes
E       assert 0

test_module.py:13: AssertionError
========================= short test summary info ==========================
FAILED test_module.py::test_ehlo - assert 0
FAILED test_module.py::test_noop - assert 0
============================ 2 failed in 0.12s =============================

您会看到两个 ​​assert 0​​ 失败,更重要的是,您还可以看到完全相同的 ​​smtp_connection​​ 对象被传递到两个测试函数中,因为 pytest 在回溯中显示了传入的参数值。 因此,使用 ​​smtp_connection​的两个测试函数的运行速度与单个测试函数一样快,因为它们重用了相同的实例。

如果你想要一个会话作用域的​​smtp_connection​​实例,你可以简单地声明它:

@pytest.fixture(scope="session")
def smtp_connection():
    # the returned fixture value will be shared for
    # all tests requesting it
    ...

Fixture作用域

​​fixture​​在第一次被测试请求时被创建,并根据它们的作用域被销毁:

  • ​​function​​:默认作用域,​​fixture​​在测试结束时销毁。
  • ​​class​​:在​class​中的最后一个测试拆除期间,​​fixture​​被销毁。
  • ​​module​​:在​module​的最后一次测试拆卸时,​​fixture​​被破坏。
  • ​​package​​:在​package​中的最后一次测试拆卸时,​​fixture​​被破坏。
  • ​​session​​:​fixture​在测试session结束时被销毁。

Pytest一次只缓存一个​​fixture​​的一个实例,这意味着当使用参数化的​​fixture​​时,Pytest可以在给定范围内多次调用一个​​fixture​​。

动态作用域

在某些情况下,您可能希望更改​​fixture​​的作用域而不更改代码。为此,将一个可调用对象传递给​​scope​​。该可调用对象必须返回一个具有有效作用域的字符串,并且只会执行一次——在​​fixture​​定义期间。它将使用两个关键字参数调用——​​fixture_name​​作为字符串,​​config​​使用配置对象。

这在处理需要时间安装的​​fixture​​时特别有用,比如生成一个​​docker​​容器。您可以使用命令行参数来控制派生容器在不同环境下的作用域。参见下面的示例。

def determine_scope(fixture_name, config):
    if config.getoption("--keep-containers", None):
        return "session"
    return "function"


@pytest.fixture(scope=determine_scope)
def docker_container():
    yield spawn_container()


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号