2017-08-08 145 views
1

是否有办法指定pytestpytest.mark.parametrize()参数的可调用参数,以便仅在选择运行测试时动态生成参数?如何使用callable作为pytest参数ize()参数?

我有一些昂贵的操作要执行以生成参数,我只想执行它们,如果测试被选中运行。

例如,

import pytest 

def my_callable(): 
    # do expensive operations here 
    return [(1, 2), (3, 6)] 


# I want my_callable to be called only if test_something 
# has been selected to be run 
@pytest.mark.parametrize("my_parm_1,my_parm_2", my_callable) 
def test_something(my_parm_1, my_parm_2): 
    assert my_parm_1 * 2 == my_parm_2 
+0

这一切似乎都是pytest方面的一个小缺陷。也许值得考虑用pytest提交一个bug,以便延迟评估参数到装饰测试运行的时刻(或者添加一个装饰参数来实现这一点)... – sophros

回答

0

,而不是直接使用@pytest.mark.parametrizemycallable,你可以创建一个代理:

def my_callable(): 
    # do expensive operations here 
    return [(1, 2), (3, 6)] 

expensive_params = [paramset for paramset in my_callable()] 

@pytest.mark.parametrize("my_parm_1,my_parm_2", expensive_params) 
... 
+0

适用于Python 3.6.1和pytest 3.2 .0 – sophros

+1

但是如果“我只想在测试被选择运行时执行它们”呢? 'expensive_params'是全局变量,即使未选择测试,它也会始终被评估,不是吗? –

+0

同意。 'expensive_params'总是在编译时进行评估,而我希望只在测试运行时才评估它。 –

0

我想这是你想要的东西 - 昂贵的计算是灯具内部哪些仅在调用测试并且昂贵的计算仅进行一次时才被调用:

class TestSomething: 

    _result = None 

    @pytest.fixture() 
    def my_callable(self): 
     if TestSomething._result is None: 
      # do expensive operations here 
      TestSomething._result = [(1, 2), (3, 6)] 

     def _my_callable(run_number): 
      return TestSomething._result[run_number] 
     return _my_callable 

    @pytest.mark.parametrize("run_number", [0, 1]) 
    def test_something(self, run_number, my_callable): 
     my_param_1, my_param_2 = my_callable(run_number) 
     assert my_param_1 * 2 == my_param_2 
+0

尽管这会将昂贵的操作移动到测试运行时,但它还会强制代码事先知道由my_callable()返回的可迭代的长度。不幸的是,我不知道迭代器的长度 - 昂贵的操作动态地决定了迭代器的长度。 Iteresting解决方案,但它不完全符合我的要求。 此外,这个解决方案没有在用pytest -v运行时看到测试名称中的参数值的好处。只会看到“run_number”。 –

+0

@RobBednark考虑到参数的数目是未知的,唯一想到的其他事情是删除'parametrize',使用上面的fixture并在测试代码内部遍历一组参数。有点难看,但它会起作用。 –

+0

是的,我考虑在单个测试中循环参数。我希望得到一个'parametrize'解决方案,其中每组参数都是它自己的测试,而不是将它们集中到一个测试中。 –