小编典典

将参数传递给灯具功能

python

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

由于tester对象是获得DLL变量和函数的引用的对象,因此我需要将DLL变量的列表传递给每个测试文件的tester对象(要记录的变量对于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属性?


阅读 161

收藏
2020-12-20

共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

但是,尽管这种形式的间接参数化是明确的,但正如@Yukihiko
Shinoda指出的那样,它现在支持一种形式的隐式间接参数化(尽管我在官方文档中找不到对此的任何明显引用):

# 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_argtester夹具却可以,因此它通过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在创建其属性后可以对其进行更新,以调整各个测试的行为。

2020-12-20