如何动态获取pytest fixture数据

时间:2016-09-13 17:30:47

标签: python pytest python-3.5 fixtures

我试图为测试单个api端点的几个测试场景定义init数据。我想这样做,这样我就不必为测试的多次迭代生成锅炉板代码,只有数据不同。我似乎无法使用内置的pytest灯具来解决这个问题。这基本上就是我想要做的事情:

在tests / conftext.py中:

import pytest

@pytest.fixture(scope="module")
def data_for_a():
    return "a_data"

@pytest.fixture(scope="module")
def data_for_b():
    return "b_data"

在tests / tests.py

import pytest

# this works
def test_a(data_for_a):
    assert "a_data" == data_for_a

# but I want to do this and it fails:
scenarios = [
    { "name": "a", "data": data_for_a },
    { "name": "b", "data": data_for_b },
]

for scenario in scenarios:
    print(scenario.name, scenario.data)

# desired output:
# "a a_data"
# "b b_data"

我收到NameError: name 'data_for_a' is not defined个例外。我已经尝试了各种方法来实现这一点,但似乎无法将夹具作为参数传递给测试方法 - 所以要么定义一堆样板测试,要么有一堆if /单个测试中的else语句并明确传递每个fixture。我不喜欢这些选项中的任何一个。目前我似乎只需构建自己的辅助模块来获取此测试数据,但我更倾向于使用内置机制。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:1)

您可以从conftest.py导入,如下所示:

from conftest import data_for_a, data_for_b

from conftest import *

允许您引用该函数,而不将其作为参数传递给测试函数。

修改 请注意,根据Here is an image of how I want the image to appear on the screen

,通常不建议这样做
  

如果你有conftest.py文件,这些文件不在python包目录中(即包含 __ init __。py 的文件),那么“import conftest”可能不明确,因为可能还有其他的混乱。 py文件以及PYTHONPATH或sys.path。因此,项目要么将conftest.py置于包范围内,要么永远不会从conftest.py文件中导入任何内容,这是很好的做法。

答案 1 :(得分:0)

自您发布以来已经有一段时间了,所以在您发布的时候,pytest内置这个功能的可能性很小。

我相信你所寻找的是pytest_generate_tests。您可以在conftest.py模块中定义它(放在包含要运行的测试的目录中),在通过pytest运行任何测试之前自动解析。此功能可用于参数化' [sic]您的测试功能或您的灯具动态,允许您动态定义您希望测试/灯具迭代的输入集。

我已经包含了一个例子。请考虑以下目录结构:

tests
 |
 +-- examples.py
 +-- test_examples.py
 +-- conftest.py

现在让我们看看每个文件......

# examples.py
# -----------
example_1 = {
    "friendship": 0.0,
    "totes": 0.0,
}

example_2 = {
    "friendship": 0.0,
    "totes": 0.0,
}

dont_use_me = {
    "friendship": 1.0,
    "totes": 1.0,
}

...

# test_examples.py
# ----------------
def test_answer(pydict_fixture):
    for k,v in pydict_fixture.items():
        assert v==0.0

...

# conftest.py
# -----------
from os.path import join, dirname, abspath
import imp
import re

def pytest_generate_tests(metafunc):
    this_dir    = dirname(abspath(metafunc.module.__file__))
    #
    if 'pydict_fixture' in metafunc.fixturenames:
        examples_file= join(this_dir, "examples.py")
        examples_module = imp.load_source('examples', examples_file)
        examples_regex = re.compile("example")
        examples = []
        for name, val in examples_module.__dict__.iteritems():
            if examples_regex.search(name):
                examples.append(val)
        metafunc.parametrize('pydict_fixture', examples)

在这个特定的例子中,我想在一个单独的文件中管理测试用例。所以,我写了一个pytest_generate_tests函数,在运行任何测试之前,解析examples.py,创建一个字典列表,其名称包括单词' example&#39 ;和,强制test_answer在列表中的每个字典上运行。因此,test_answer将被调用两次,一次在example_1上,一次在example_2上。两项测试都将通过。

这是它的快速简短。最重要的是输入列表是在pytest_generate_tests内动态确定的,测试在列表中的每个项目上运行一次。

但是,为了在我对此处所写内容的描述中完整,我的pytest_generate_tests函数实际上为每个测试函数创建了一个输入列表(由pytest表示#metafunc中预定义的pytest_generate_tests变量使用虚pydict_fixture,并在examples.py目录中查找metafunc文件驻留!因此,可能会扩展为对一堆不同的examples.py文件运行一系列不同的测试。