Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在py.test中将多个参数化夹具连接到一个新夹具中?_Python_Fixtures_Pytest - Fatal编程技术网

Python 如何在py.test中将多个参数化夹具连接到一个新夹具中?

Python 如何在py.test中将多个参数化夹具连接到一个新夹具中?,python,fixtures,pytest,Python,Fixtures,Pytest,如果我有两个参数化的fixture,我如何创建一个单独的测试函数,首先用一个fixture的实例调用,然后用另一个fixture的实例调用 我想创建一个新的装置,以某种方式连接两个现有装置是有意义的。这对“正常”装置很有效,但我似乎无法使其与参数化装置一起工作 下面是我尝试的一个简化示例: import pytest @pytest.fixture(params=[1, 2, 3]) def lower(request): return "i" * request.param @py

如果我有两个参数化的fixture,我如何创建一个单独的测试函数,首先用一个fixture的实例调用,然后用另一个fixture的实例调用

我想创建一个新的装置,以某种方式连接两个现有装置是有意义的。这对“正常”装置很有效,但我似乎无法使其与参数化装置一起工作

下面是我尝试的一个简化示例:

import pytest

@pytest.fixture(params=[1, 2, 3])
def lower(request):
    return "i" * request.param

@pytest.fixture(params=[1, 2])
def upper(request):
    return "I" * request.param

@pytest.fixture(params=['lower', 'upper'])
def all(request):
    return request.getfuncargvalue(request.param)

def test_all(all):
    assert 0, all
当我运行此命令时,会出现以下错误:

request = <SubRequest 'lower' for <Function 'test_all[lower]'>>

    @pytest.fixture(params=[1, 2, 3])
    def lower(request):
>       return "i" * request.param
E       AttributeError: 'SubRequest' object has no attribute 'param'
但是,请注意,在一些复杂的情况下,它将不起作用:

相关测试问题:


    • 它并不美丽,但也许今天你知道更好的方法

      “all”装置内的请求对象只知道自己的参数:“lower”、“upper”。单程

      我得到了完全相同的结果(并且收到了一份类似但不同的报告)。我能想出的最好的解决办法是重新考虑如何将我的测试参数化。我没有使用具有兼容输出的多个fixture,而是将fixture用作常规函数,并将元fixture参数化以接受函数名和参数:

      import pytest
      
      def lower(n):
          return 'i' * n
      
      def upper(n):
          return 'I' * n
      
      @pytest.fixture(params=[
          (lower, 1),
          (lower, 2),
          (upper, 1),
          (upper, 2),
          (upper, 3),
      ])
      def all(request):
          func, *n = request.param
          return func(*n)
      
      def test_all(all):
          ...
      
      在您的特定情况下,将
      n
      解包到一个列表中并将其与
      *
      一起传递有点过分,但它提供了通用性。我的案例中的装置都接受不同的参数列表

      在pytest允许我们正确地链接夹具之前,这是我提出的唯一方法,可以在您的情况下运行5个测试,而不是12个。您可以使用以下方法缩短列表:

      @pytest.fixture(params=[
          *[(lower, i) for i in range(1, 3)],
          *[(upper, i) for i in range(1, 4)],
      ])
      

      这样做有一个实际的好处。如果管道中有其他依赖项,您可以选择要对哪些测试执行特殊操作,如XFAIL,而不影响整个其他测试。

      现在在
      pytestcases
      中有一个解决方案,名为
      fixture\u union
      。以下是如何创建示例中请求的装置联合:

      from pytest_cases import fixture_union, pytest_fixture_plus
      
      @pytest_fixture_plus(params=[1, 2, 3])
      def lower(request):
          return "i" * request.param
      
      @pytest_fixture_plus(params=[1, 2])
      def upper(request):
          return "I" * request.param
      
      fixture_union('all', ['lower', 'upper'])
      
      def test_all(all):
          print(all)
      
      它按预期工作:

      <...>::test_all[lower-1] 
      <...>::test_all[lower-2] 
      <...>::test_all[lower-3] 
      <...>::test_all[upper-1] 
      <...>::test_all[upper-2] 
      

      有关详细信息,请参阅。(顺便说一句,我是作者;)

      我看到py.test tracker上有一个可能解决我问题的插件,但是py.test开发人员还没有响应。有一个插件似乎与我的问题有关,但也没有响应……插件允许您这样做。@ChristianLong感谢您的提示!我已经在上面添加了一些信息。谢谢你的回答!但是使用
      lower
      upper
      作为
      all()
      的函数参数会对
      lower()
      upper()
      的所有组合(我想更准确地说是笛卡尔积)运行测试,即6次。将两个
      params
      添加到
      all()
      将使数字加倍,即
      test\u all()
      运行12次。我只希望将
      lower()
      upper()
      连接起来,即只运行测试5次。那么夹具的要点是它们可以重复使用,对吗?如果我创建一个参数化的装置,我还想重复使用参数化(因为它是装置的一部分)。按照你的建议,我不能重复使用参数化。假设有更多的装置,如
      下部
      上部
      ,我想将它们组合成几种不同的装置。这个插件让我无需手动重复任何操作就可以做到这一点。
      from pytest_cases import fixture_union, pytest_fixture_plus
      
      @pytest_fixture_plus(params=[1, 2, 3])
      def lower(request):
          return "i" * request.param
      
      @pytest_fixture_plus(params=[1, 2])
      def upper(request):
          return "I" * request.param
      
      fixture_union('all', ['lower', 'upper'])
      
      def test_all(all):
          print(all)
      
      <...>::test_all[lower-1] 
      <...>::test_all[lower-2] 
      <...>::test_all[lower-3] 
      <...>::test_all[upper-1] 
      <...>::test_all[upper-2] 
      
      import pytest
      from pytest_cases import NOT_USED
      
      @pytest.fixture(params=[1, 2])
      def upper(request):
          # this fixture does not use pytest_fixture_plus 
          # so we have to explicitly discard the 'NOT_USED' cases
          if request.param is not NOT_USED:
              return "I" * request.param