关于 fixture

另请参阅

如何使用 fixture

另请参阅

fixture 参考

pytest fixture 的设计目标是明确、模块化和可扩展。

什么是 fixture

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

fixture 定义了构成测试安排阶段的步骤和数据(请参阅测试剖析)。在 pytest 中,它们是您定义用于此目的的函数。它们还可用于定义测试的行为阶段;这是一种设计更复杂测试的强大技术。

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

我们可以通过使用@pytest.fixture装饰函数来告诉 pytest 某个特定函数是一个 fixture。下面是一个 pytest 中 fixture 的简单示例

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

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

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

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

  • fixture 具有明确的名称,并且通过声明从测试函数、模块、类或整个项目中使用它们来激活。

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

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

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

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

fixture 错误

pytest 会尽力将给定测试的所有 fixture 按线性顺序排列,以便它可以看到哪个 fixture 先发生,哪个 fixture 后发生,依此类推。但是,如果较早的 fixture 出现问题并引发异常,pytest 将停止执行该测试的 fixture,并将该测试标记为有错误。

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

这就是尽可能为给定测试剔除不必要依赖项的一个好主意的原因。这样,无关问题就不会导致我们对可能或不可能出现问题的情况产生不完整的了解。

下面是一个快速示例,有助于解释

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) 出现错误并引发异常,我们将无法知道 order.extend([2])order += [3] 是否也会出现问题。在 append_first 引发异常后,pytest 将不再为 test_order 运行任何其他 fixture,甚至不会尝试运行 test_order 本身。唯一会运行的是 orderappend_first

共享测试数据

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

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

关于 fixture 清理的说明

pytest 不会对 SIGTERMSIGQUIT 信号执行任何特殊处理(SIGINT 由 Python 运行时通过 KeyboardInterrupt 自然处理),因此管理外部资源的 fixture(当 Python 进程被这些信号终止时,清除这些资源非常重要)可能会泄露资源。

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

如果您的套件中的 fixture 需要在这些场景中特别注意终止,请参阅问题跟踪器中的 此评论,了解可能的解决方法。