定义一个pytest fixture,为测试函数

时间:2017-12-27 08:18:17

标签: python unit-testing pytest fixtures

使用pytest,我可以像这样定义一个夹具:

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

并在如此的测试中使用它:

def test_blah(foo):
    assert foo == "blah"

这一切都很好。但我想要做的是定义一个“扩展”的单个fixture函数,为测试函数提供多个参数。像这样:

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

def test_stuff(foo, bar):
    assert foo == "blah" and bar == "whatever"

我想将两个对象foobar一起定义(而不是作为单独的灯具),因为它们以某种方式相关。我有时也可能想要定义一个依赖于另一个夹具的夹具,但让第二个夹具合并第一个夹具的结果并将其与其自身的附加物一起返回:

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

@pytest.multifixture("foo,bar")
def foobar():
    f = foo()
    return f, some_info_related_to(f)

这个例子看起来很愚蠢,但在某些情况下foo类似于Request对象,bar对象需要链接到同一个请求对象。 (也就是说,我无法将foobar定义为独立的装置,因为我需要从单个请求中派生两者。)

本质上,我想要做的是将fixture函数的名称与test-function参数的名称分离,这样我就可以定义一个由特定集“触发”的fixture。测试函数签名中的参数名称,而不仅仅是一个名称与fixture函数名称相同的参数。

当然,我总是可以返回一个元组作为夹具的结果,然后在测试功能中自己解压缩。但是考虑到pytest为自动匹配名称和参数提供了各种神奇的技巧,看起来它也可以神奇地处理它并不是不可想象的。用pytest可以做到这一点吗?

3 个答案:

答案 0 :(得分:1)

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

public void b() {
  CompletableFuture.runAsync(() ->  a());
  return "hello";
}

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

答案 1 :(得分: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"

因此,我们定义了pytest_generate_tests元函数。

  1. 检查 multifixture 标记是否在测试中
  2. 如果标记已启用-它会使用变量名称​​“ foo,bar” 和功能 foobar ,这些变量将在生成时执行

    @ pytest.mark.multifixture(“ foo,bar”,foobar)

答案 2 :(得分:0)

您可以使用两个 pytest 固定装置来执行此操作,如下所示:

import pytest

@pytest.fixture
def foo():
    return [object()]

# value derived from foo
@pytest.fixture
def bar(foo):
    return foo[0]

# totally independent fixture
@pytest.fixture
def baz():
    return object()


def test_fixtures(foo, bar, baz):
    assert foo[0] is bar
    assert foo[0] is not baz
    # both assertions will pass

这里的 foo 和 bar 固定装置在它们的值之间有特定的关系(引用同一个对象)。这与您希望从多台灯具中获得的结果相同。 (包含 baz 固定装置用于比较,并使用 object() 的无关实例。

如果两个值都来自某个共享上下文,您可以将共享上下文放在一个装置中,然后独立导出最终结果。

@pytest.fixture
def shared():
    return [object()]

@pytest.fixture
def derived_1(shared):
    return shared[0]

@pytest.fixture
def derived_2(shared):
    return shared[-1]

def test_derived(derived_1, derived_2):
    assert derived_1 is derived_2