【问题标题】:Dynamically parametrizing class-level fixtures with pytest使用 pytest 动态参数化类级别的固定装置
【发布时间】:2017-02-02 19:39:40
【问题描述】:

可以从命令行参数对测试函数进行参数化。 可以将一个固定装置限定为一个类。 我想将这两件事结合起来,以便每个类都接收到给类中的固定装置的参数化参数。

(本质上,根据命令行参数,我需要运行一个非常昂贵的操作,然后针对该操作的结果进行各种廉价、快速的测试,而且我不希望重新运行昂贵的操作每个便宜的测试,所以我想要一种方法来保存它)

换句话说,我正在寻找一个等效于 pytest_generate_tests(metafunc) 的方法,它可以用于动态参数化一个夹具,而不是一个测试函数。

我已经尝试过的一件事是读取请求参数并通过 pytest_generate_tests 钩子设置 那些

conftest.py:
    def pytest_generate_tests(metafunc):
        metafunc.parametrize("result", [
                (1,0),(1,2)
            ])

test_thing.py:
    class TestThingy:
        @pytest.fixture(scope="class")
        def result(self, request):
            a,b=request.param
            return a+b

    #@pytest.mark.parametrize("result", [(0, 1), (1, 2)])
    def test_one(self, result):
        assert result!=2

运行此测试会引发以下错误(请注意,当我在没有 conftest 钩子且未注释注释行的情况下尝试测试时,测试运行良好):

@pytest.fixture(scope="class")
def result(self, request):
    a,b=request.param

AttributeError: 'SubRequest' 对象没有属性 'param'

我也对任何其他实现相同结果的替代方法感兴趣。

【问题讨论】:

  • 如果 py.test 团队能够参与进来,那就太好了。文档在这一点上根本不清楚。

标签: python testing pytest fixture


【解决方案1】:

我已经完成了一项丑陋的工作,基于这样的命令行参数对夹具进行参数化:

# contents of conftest.py
import pytest

def pytest_addoption(parser):
    parser.addoption("--test-local", action="store_true", default=False)

def pytest_generate_tests(metafunc):
    if "dummy" in metafunc.fixturenames:
        #driverParams sets dummy[0], dummy[1] parametrically (as seen below)
        if metafunc.config.getoption("--test-local"):
            driverParams = [(True, None)]
        else:
            driverParams = [(False, "seriousface setting 1"), 
                            (False, "seriousface setting 2")]
        metafunc.parametrize("dummy", driverParams)

#driver can then be used as a standard fixture
@pytest.fixture(scope="function")
def driver(dummy):
    _driver = makeDriverStuff(dummy[0], dummy[1])
    yield _driver
    _driver.cleanup()

@pytest.fixture(scope="function")
def dummy():
    pass

基本上这里发生的事情是,当metafunc.parametrize("dummy", driverParams) 运行时,它会将driverParams 扔到任何依赖于虚拟夹具的东西中。更重要的是,这意味着 虚拟夹具函数永远不会真正执行

最初,我尝试使用 metafunc 直接参数化我的驱动程序夹具,并注意到清理从未发生过,因为我之前做事的(错误)方式是直接使用 metafunc.parametrizemakeDriverStuff(param1, param2),然后从头开始头想知道为什么driver() 从未被调用。假人的重点是说,“嘿,这里有一个合法的固定装置,不要抱怨你找不到它!”,然后总是用真正有用的东西抢占它。

就像我说的,这是一个丑陋的 hack。但你应该能够适应它

【讨论】:

  • 我实施了这个建议。然后我添加了一个打印语句来检查调用昂贵代码的次数。不幸的是,对于每个获取参数的测试,答案都是一遍又一遍。
  • 就我正在做的事情而言,这是故意的。我的 makeDriverStuff() 启动了一个新的 WebDriver(因此是一个新的浏览器实例),这是我特别想要的,以便测试彼此之间更加隔离。
  • 是否将灯具装饰器更改为让scope="session"(或类或模块,视情况而定)为您解决问题?
猜你喜欢
  • 2019-04-03
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 2020-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多