关于夹具

另请参阅

如何使用夹具

另请参阅

夹具参考

pytest 夹具旨在实现显式、模块化和可伸缩性。

什么是夹具

在测试中,夹具为测试提供了一个定义明确、可靠且一致的上下文。这可以包括环境(例如配置了已知参数的数据库)或内容(例如数据集)。

夹具定义了构成测试准备阶段的步骤和数据(参阅测试剖析)。在 pytest 中,它们是您为此目的定义的函数。它们也可以用于定义测试的执行阶段;这是设计更复杂测试的强大技术。

夹具设置的服务、状态或其他操作环境通过参数供测试函数访问。对于测试函数使用的每个夹具,测试函数的定义中通常会有一个参数(以夹具命名)。

我们可以通过使用@pytest.fixture装饰器来告诉 pytest 某个特定函数是一个夹具。这是一个 pytest 夹具可能样子的简单示例

import pytest


class Fruit:
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        return self.name == other.name


@pytest.fixture
def my_fruit():
    return Fruit("apple")


@pytest.fixture
def fruit_basket(my_fruit):
    return [Fruit("banana"), my_fruit]


def test_my_fruit_in_basket(my_fruit, fruit_basket):
    assert my_fruit in fruit_basket

测试也不必局限于单个夹具。它们可以依赖任意数量的夹具,并且夹具也可以使用其他夹具。这正是 pytest 夹具系统真正出彩的地方。

相对于 xUnit 风格设置/拆解函数的改进

pytest 夹具相对于经典的 xUnit 风格设置/拆解函数提供了显著的改进

  • 夹具具有显式名称,并通过在测试函数、模块、类或整个项目中声明其使用来激活。

  • 夹具以模块化的方式实现,因为每个夹具名称都会触发一个夹具函数,该函数本身可以使用其他夹具。

  • 夹具管理可以从简单的单元测试扩展到复杂的函数测试,允许根据配置和组件选项参数化夹具和测试,或在函数、类、模块或整个测试会话范围内重用夹具。

  • 拆解逻辑可以轻松、安全地管理,无论使用了多少夹具,而无需手动仔细处理错误或微观管理清理步骤的添加顺序。

此外,pytest 继续支持如何实现 xUnit 风格的设置。您可以混合使用这两种风格,根据您的偏好,逐步从经典风格过渡到新风格。您也可以从现有的unittest.TestCase 风格开始。

夹具错误

pytest 尽力将给定测试的所有夹具按线性顺序排列,以便它能看到哪个夹具先发生、哪个其次等等。但是,如果一个较早的夹具出现问题并引发异常,pytest 将停止为该测试执行夹具,并将该测试标记为有错误。

当一个测试被标记为有错误时,这并不意味着测试失败。它只是意味着测试甚至无法尝试,因为其依赖项之一出现了问题。

这就是为什么最好为给定测试尽可能多地剔除不必要的依赖项的原因之一。这样,不相关的问题就不会导致我们对可能存在的问题或不存在的问题有不完整的认识。

这里有一个简单的例子来帮助解释

import pytest


@pytest.fixture
def order():
    return []


@pytest.fixture
def append_first(order):
    order.append(1)


@pytest.fixture
def append_second(order, append_first):
    order.extend([2])


@pytest.fixture(autouse=True)
def append_third(order, append_second):
    order += [3]


def test_order(order):
    assert order == [1, 2, 3]

如果由于某种原因,order.append(1) 有一个 bug 并引发了异常,我们就无法知道 order.extend([2])order += [3] 是否也会有问题。append_first 抛出异常后,pytest 将不再为 test_order 运行任何夹具,甚至不会尝试运行 test_order 本身。唯一会运行的只有 orderappend_first

共享测试数据

如果您想让测试文件中的数据可供您的测试使用,一个好方法是将这些数据加载到夹具中供您的测试使用。这利用了 pytest 的自动缓存机制。

另一个好方法是将数据文件添加到 tests 文件夹中。还有一些社区插件可以帮助管理测试的这一方面,例如 pytest-datadirpytest-datafiles

关于夹具清理的注意事项

pytest 不对 SIGTERMSIGQUIT 信号进行任何特殊处理(SIGINT 通过 KeyboardInterrupt 由 Python 运行时自然处理),因此,管理在 Python 进程终止时(由这些信号)需要清除的外部资源的夹具可能会导致资源泄漏。

pytest 不处理这些信号来执行夹具清理的原因是信号处理程序是全局的,更改它们可能会干扰正在执行的代码。

如果您的测试套件中的夹具在这些场景下需要特别注意终止处理,请参阅问题追踪器中的此评论以获取可能的解决方案。