定义一个 pytest 夹具,为测试函数提供多个参数

Bre*_*arn 7 python unit-testing fixtures pytest

使用 pytest,我可以像这样定义一个装置:

@pytest.fixture
def foo():
    return "blah"
Run Code Online (Sandbox Code Playgroud)

并在像这样的测试中使用它:

def test_blah(foo):
    assert foo == "blah"
Run Code Online (Sandbox Code Playgroud)

这一切都很好。但是我想要做的是定义一个“扩展”以向测试函数提供多个参数的单一夹具函数。像这样的东西:

@pytest.multifixture("foo,bar")
def foobar():
    return "blah", "whatever"

def test_stuff(foo, bar):
    assert foo == "blah" and bar == "whatever"
Run Code Online (Sandbox Code Playgroud)

我要定义的两个对象foobar在一起(不作为单独的固定装置),因为它们都以某种方式相关。有时我可能还想定义一个依赖于另一个夹具的夹具,但让第二个夹具合并第一个夹具的结果并将其与自己的添加一起返回:

@pytest.fixture
def foo():
    return "blah"

@pytest.multifixture("foo,bar")
def foobar():
    f = foo()
    return f, some_info_related_to(f)
Run Code Online (Sandbox Code Playgroud)

这个例子可能看起来很傻,但在某些情况下foo就像一个请求对象,并且该bar对象需要链接到同一个请求对象。(也就是说,我不能将foo和定义bar为独立的装置,因为我需要从单个请求派生。)

本质上,我想要做的是将夹具函数的名称与测试函数参数的名称分离,以便我可以定义一个夹具,该夹具由测试函数签名中的一特定参数名称“触发” ,而不仅仅是名称与夹具函数名称相同的单个参数。

当然,我总是可以只返回一个元组作为夹具的结果,然后自己在测试函数中解压它。但是考虑到 pytest 提供了各种神奇的技巧来自动将名称与参数匹配,看起来它也可以神奇地处理这个问题似乎并非不可想象。pytest 可以实现这样的事情吗?

sma*_*rie 6

您现在可以使用pytest-cases执行此操作:

from pytest_cases import fixture

@fixture(unpack_into="foo,bar")
def foobar():
    return "blah", "whatever"

def test_stuff(foo, bar):
    assert foo == "blah" and bar == "whatever"
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅文档(顺便说一下,我是作者)


iHe*_*los 0

注意:如果您的灯具依赖于另一个带有参数的灯具,则此解决方案不起作用

真的不知道 pytest 包中是否有任何默认解决方案,但您可以自定义一个:

import pytest
from _pytest.mark import MarkInfo


def pytest_generate_tests(metafunc):
    test_func = metafunc.function
    if 'use_multifixture' in [name for name, ob in vars(test_func).items() if isinstance(ob, MarkInfo)]:
        result, func = test_func.use_multifixture.args
        params_names = result.split(',')
        params_values = list(func())
        metafunc.parametrize(params_names, [params_values])


def foobar():
    return "blah", "whatever"


@pytest.mark.use_multifixture("foo,bar", foobar)
def test_stuff(foo, bar):
    assert foo == "blah" and bar == "whatever"


def test_stuff2():
    assert 'blah' == "blah"
Run Code Online (Sandbox Code Playgroud)

所以我们定义了 pytest_generate_tests 元函数。这个功能

  1. 检查测试上是否有多夹具标记
  2. 如果标记打开 - 它采用变量名称“foo,bar”和函数foobar将在生成时执行

    @pytest.mark.multifixture("foo,bar", foobar)