考虑以下Pytest:
import pytest
class TimeLine(object):
instances = [0, 1, 2]
@pytest.fixture
def timeline():
return TimeLine()
def test_timeline(timeline):
for instance in timeline.instances:
assert instance % 2 == 0
if __name__ == "__main__":
pytest.main([__file__])
Run Code Online (Sandbox Code Playgroud)
该测试test_timeline使用Pytest fixture timeline,它本身具有该属性instances.此属性在测试中迭代,因此只有断言适用于每个输入时instance,测试才会通过timeline.instances.
然而,我真正想要做的是生成3个测试,其中2个应该通过,其中1个将失败.我试过了
@pytest.mark.parametrize("instance", timeline.instances)
def test_timeline(timeline):
assert instance % 2 == 0
Run Code Online (Sandbox Code Playgroud)
但这会导致
AttributeError: 'function' object has no attribute 'instances'
Run Code Online (Sandbox Code Playgroud)
据我了解,在Pytest灯具中,函数"变为"它的返回值,但在测试参数化时,这似乎还没有发生.如何以理想的方式设置测试?
imi*_*ric 31
这实际上可以通过间接参数化来实现.
这个例子用pytest 3.1.2做你想要的:
import pytest
class TimeLine:
def __init__(self, instances):
self.instances = instances
@pytest.fixture
def timeline(request):
return TimeLine(request.param)
@pytest.mark.parametrize(
'timeline',
([1, 2, 3], [2, 4, 6], [6, 8, 10]),
indirect=True
)
def test_timeline(timeline):
for instance in timeline.instances:
assert instance % 2 == 0
if __name__ == "__main__":
pytest.main([__file__])
Run Code Online (Sandbox Code Playgroud)
另见这个类似的问题.
sma*_*rie 18
这是一个令人困惑的话题,因为人们往往认为灯具和参数是一回事。它们不是,甚至不会在 pytest 运行的同一阶段收集。按照设计,参数是在收集测试时收集的(测试节点列表正在构建中),而夹具则是在测试节点运行时执行(测试节点列表是固定的,不能修改)。所以夹具内容不能用来改变测试节点的数量——这就是参数的作用。另请参阅我的详细答案here。
这就是为什么您的问题没有“原样”解决方案的原因:您应该将Timeline实例放在参数中,而不是放在夹具中。像这样:
import pytest
class TimeLine(object):
instances = [0, 1, 2]
@pytest.fixture(params=TimeLine().instances)
def timeline(request):
return request.param
def test_timeline(timeline):
assert timeline % 2 == 0
Run Code Online (Sandbox Code Playgroud)
Kurt Peek 的回答提到了另一个主题,恕我直言在这里增加了混淆,因为它与您的问题没有直接关系。既然它被提及,甚至被接受为解决方案,让我详细说明一下:确实在 pytest 中,您不能在@pytest.mark.parametrize. 但即使你能做到,也不会改变任何事情。
由于此功能现在pytest-cases作为测试版提供(我是作者),您可以自己尝试一下。即使使用该功能,使您的示例工作的唯一方法仍然相同:从夹具中删除列表。所以你最终得到:
import pytest
from pytest_cases import parametrize, fixture_ref
class TimeLine(object):
instances = [0, 1, 2]
@pytest.fixture(params=TimeLine().instances)
def timeline(request):
return request.param
@parametrize("t", [fixture_ref(timeline)])
def test_timeline(t):
assert t % 2 == 0
Run Code Online (Sandbox Code Playgroud)
这与前面的示例相同,但有一个额外的,可能没用的层。注意:另请参阅此讨论。
Kur*_*eek 15
从Using fixtures in pytest.mark.parametrize pytest issue 来看,目前似乎无法在pytest.mark.parametrize.
hwj*_*wjp 12
而不是间接参数化,或者下面涉及继承的hacky解决方案,你也可以使用params参数@pytest.fixture()- 我认为这是最简单的解决方案吗?
import pytest
class TimeLine:
def __init__(self, instances=[0, 0, 0]):
self.instances = instances
@pytest.fixture(params=[
[1, 2, 3], [2, 4, 5], [6, 8, 10]
])
def timeline(request):
return TimeLine(request.param)
def test_timeline(timeline):
for instance in timeline.instances:
assert instance % 2 == 0
Run Code Online (Sandbox Code Playgroud)
https://docs.pytest.org/en/latest/fixture.html#parametrizing-fixtures
香草 pytest 是可能的
测试数字.py
import pytest
@pytest.fixture(params=[1, 2, 3, 4, 5])
def number(request):
yield request.param
def test_number_is_integer(number):
assert isinstance(number, int)
Run Code Online (Sandbox Code Playgroud)
输出
test_numbers.py::test_number_is_integer[1] PASSED
test_numbers.py::test_number_is_integer[2] PASSED
test_numbers.py::test_number_is_integer[3] PASSED
test_numbers.py::test_number_is_integer[4] PASSED
test_numbers.py::test_number_is_integer[5] PASSED
Run Code Online (Sandbox Code Playgroud)
间接参数化的使用是可行的,但是我发现有必要使用request.param一个魔术的,未命名的变量有点尴尬。
这是我使用的模式。可以说,它以不同的方式很尴尬,但是也许您也会喜欢它!
import pytest
class TimeLine:
def __init__(self, instances):
self.instances = instances
@pytest.fixture
def instances():
return [0, 0, 0]
@pytest.fixture
def timeline(instances):
return TimeLine(instances)
@pytest.mark.parametrize('instances', [
[1, 2, 3], [2, 4, 5], [6, 8, 10]
])
def test_timeline(timeline):
for instance in timeline.instances:
assert instance % 2 == 0
Run Code Online (Sandbox Code Playgroud)
该timeline固定装置取决于另一个称为的固定装置instances,其默认值是[0,0,0],但是在实际测试中,我们使用parametrize注入一系列不同的值instances。
我所看到的优点是,每个事物都有一个好名字,而且您不需要传递该indirect=True标志。
| 归档时间: |
|
| 查看次数: |
17831 次 |
| 最近记录: |