小编典典

将参数传递给夹具函数

all

我正在使用 py.test 测试一些包装在 python 类 MyTester 中的 DLL
代码。出于验证目的,我需要在测试期间记录一些测试数据,然后再进行更多处理。因为我有很多 test_…
文件,所以我想为我的大多数测试重用测试器对象创建(MyTester 的实例)。

由于测试器对象是获得对 DLL 变量和函数的引用的对象,因此我需要将 DLL 变量列表传递给每个测试文件的测试器对象(要记录的变量对于 test_.. 。
文件)。列表的内容用于记录指定的数据。

我的想法是这样做:

import pytest

class MyTester():
    def __init__(self, arg = ["var0", "var1"]):
        self.arg = arg
        # self.use_arg_to_init_logging_part()

    def dothis(self):
        print "this"

    def dothat(self):
        print "that"

# located in conftest.py (because other test will reuse it)

@pytest.fixture()
def tester(request):
    """ create tester object """
    # how to use the list below for arg?
    _tester = MyTester()
    return _tester

# located in test_...py

# @pytest.mark.usefixtures("tester") 
class TestIt():

    # def __init__(self):
    #     self.args_for_tester = ["var1", "var2"]
    #     # how to pass this list to the tester fixture?

    def test_tc1(self, tester):
       tester.dothis()
       assert 0 # for demo purpose

    def test_tc2(self, tester):
       tester.dothat()
       assert 0 # for demo purpose

是否有可能像这样实现它,或者是否有更优雅的方式?

通常我可以使用某种设置功能(xUnit 样式)为每种测试方法执行此操作。但我想获得某种重用。有谁知道这是否可以通过固定装置实现?

我知道我可以做这样的事情:(来自文档)

@pytest.fixture(scope="module", params=["merlinux.eu", "mail.python.org"])

但我需要直接在测试模块中进行参数化。 是否可以从测试模块访问夹具的 params 属性?


阅读 81

收藏
2022-07-12

共1个答案

小编典典

更新: 由于这是对这个问题的公认答案,并且有时仍然会被赞成,我应该添加一个更新。尽管我的原始答案(如下)是在旧版本的 pytest
中执行此操作的唯一方法,因为其他人已经注意到pytest现在支持夹具的间接参数化。例如你可以做这样的事情(通过@imiric):

# test_parameterized_fixture.py
import pytest

class MyTester:
    def __init__(self, x):
        self.x = x

    def dothis(self):
        assert self.x

@pytest.fixture
def tester(request):
    """Create tester object"""
    return MyTester(request.param)


class TestIt:
    @pytest.mark.parametrize('tester', [True, False], indirect=['tester'])
    def test_tc1(self, tester):
       tester.dothis()
       assert 1



$ pytest -v test_parameterized_fixture.py
================================================================================= test session starts =================================================================================
platform cygwin -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: .
collected 2 items

test_parameterized_fixture.py::TestIt::test_tc1[True] PASSED                                                                                                                    [ 50%]
test_parameterized_fixture.py::TestIt::test_tc1[False] FAILED

然而,尽管这种间接参数化形式是明确的,正指出的那样,它现在支持一种隐式间接参数化形式(尽管我在官方文档中找不到任何明显的参考):

# test_parameterized_fixture2.py
import pytest

class MyTester:
    def __init__(self, x):
        self.x = x

    def dothis(self):
        assert self.x

@pytest.fixture
def tester(tester_arg):
    """Create tester object"""
    return MyTester(tester_arg)


class TestIt:
    @pytest.mark.parametrize('tester_arg', [True, False])
    def test_tc1(self, tester):
       tester.dothis()
       assert 1



$ pytest -v test_parameterized_fixture2.py
================================================================================= test session starts =================================================================================
platform cygwin -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: .
collected 2 items

test_parameterized_fixture2.py::TestIt::test_tc1[True] PASSED                                                                                                                   [ 50%]
test_parameterized_fixture2.py::TestIt::test_tc1[False] FAILED

我不确切知道这种形式的语义是什么,但似乎pytest.mark.parametrize认识到虽然该test_tc1方法不采用名为
的参数tester_arg,但它使用的tester夹具确实如此,因此它通过tester夹具传递参数化参数。


我有一个类似的问题——我有一个名为 的夹具test_package,后来我希望能够在特定测试中运行该夹具时将一个可选参数传递给该夹具。例如:

@pytest.fixture()
def test_package(request, version='1.0'):
    ...
    request.addfinalizer(fin)
    ...
    return package

(对于这些目的,夹具的作用或返回的对象类型无关紧要package)是。

然后希望以某种方式在测试函数中使用此夹具,以便我还可以指定该version夹具的参数以用于该测试。这目前是不可能的,但可能是一个不错的功能。

与此同时,很容易让我的夹具简单地返回一个 函数 ,该函数完成夹具以前所做的所有工作,但允许我指定version参数:

@pytest.fixture()
def test_package(request):
    def make_test_package(version='1.0'):
        ...
        request.addfinalizer(fin)
        ...
        return test_package

    return make_test_package

现在我可以在我的测试功能中使用它,例如:

def test_install_package(test_package):
    package = test_package(version='1.1')
    ...
    assert ...

等等。

OP 尝试的解决方案朝着正确的方向前进,正如@hpk42
的回答所暗示的那样,MyTester.__init__可以只存储对请求的引用,例如:

class MyTester(object):
    def __init__(self, request, arg=["var0", "var1"]):
        self.request = request
        self.arg = arg
        # self.use_arg_to_init_logging_part()

    def dothis(self):
        print "this"

    def dothat(self):
        print "that"

然后使用它来实现夹具,如:

@pytest.fixture()
def tester(request):
    """ create tester object """
    # how to use the list below for arg?
    _tester = MyTester(request)
    return _tester

如果需要,MyTester可以对类进行一些重组,以便.args在创建后更新其属性,以调整单个测试的行为。

2022-07-12