从 pytest fixture 返回多个对象
Returning multiple objects from a pytest fixture
我正在通过测试一个简单的事件发射器实现来学习如何使用 pytest。
基本上是这样的
class EventEmitter():
def __init__(self):
...
def subscribe(self, event_map):
# adds listeners to provided in event_map events
def emit(self, event, *args):
# emits event with given args
为了方便起见,我创建了一个 Listener
class 用于测试
class Listener():
def __init__(self):
...
def operation(self):
# actual listener
目前,测试如下所示
@pytest.fixture
def event():
ee = EventEmitter()
lstr = Listener()
ee.subscribe({"event" : [lstr.operation]})
return lstr, ee
def test_emitter(event):
lstr = event[0]
ee = event[1]
ee.emit("event")
assert lstr.result == 7 # for example
为了测试事件发射器,我需要检查事件传播后监听器的内部状态是否发生了变化。因此,我需要两个对象,我想知道是否有更好的方法来做到这一点(也许使用两个固定装置而不是一个固定装置)因为这对我来说有点难看。
在这种情况下,您可能需要两个灯具。
您可以尝试 @pytest.yield_fixture
,例如:
@pytest.yield_fixture
def event():
...
yield <event_properties>
@pytest.yield_fixture
def listener(event):
...
yield <listener_properties>
通常为了避免tuples
和美化你的代码,你可以将它们重新组合成一个单元作为一个class,这已经为你完成了,使用collections.namedtuple
:
import collections
EventListener = collections.namedtuple('EventListener', 'event listener')
现在修改你的夹具:
@pytest.fixture
def event_listener():
e = EventListener(EventEmitter(), Listener())
e.event.subscribe({'event' : [e.listener.operation]})
return e
现在修改你的测试:
def test_emitter(event_listener):
event_listener.event.emit('event')
assert event_listener.listener.result == 7
您应该在变量中使用名为 iterable unpacking 的 Python 功能。
def test_emitter(event):
lstr, ee = event # unpacking
ee.emit("event")
assert lstr.result == 7
基本上,您将 event[0]
分配给 lstr
,将 event[1]
分配给 ee
。使用此功能是避免使用索引的一种非常优雅的方式。
丢弃
如果你打算在多个测试中使用你的夹具,并且你不需要在每个测试中使用所有值,如果你对使用它们不感兴趣,你也可以丢弃 iterable 的一些元素,如下所示:
l = ['a', 'b', 'c', 'd']
a, b, c, d = l # unpacking all elements
a, _, c, d = l # discarding b
a, _, _, d = l # python 2: discard b and c
a, *_, d = l # python 3: discard b and c
a, _, _, _ = l # python2: discard, b, c and d
a, *_ = l # python3: discard b, c, and d
理论上,你不是字面上的丢弃值,而是in Python_
,so-called“我不在乎”,用于忽略特定值。
如果买不起就随便, you can now "unpack" a tuple or list fixture into other fixtures using my pytest-cases
plugin as explained in this answer.
对于您的示例,它看起来像:
from pytest_cases import pytest_fixture_plus
@pytest_fixture_plus(unpack_into="lstr,ee")
def event():
ee = EventEmitter()
lstr = Listener()
ee.subscribe({"event" : [lstr.operation]})
return lstr, ee
def test_emitter(lstr, ee):
ee.emit("event")
assert lstr.result == 7 # for example
我正在通过测试一个简单的事件发射器实现来学习如何使用 pytest。
基本上是这样的
class EventEmitter():
def __init__(self):
...
def subscribe(self, event_map):
# adds listeners to provided in event_map events
def emit(self, event, *args):
# emits event with given args
为了方便起见,我创建了一个 Listener
class 用于测试
class Listener():
def __init__(self):
...
def operation(self):
# actual listener
目前,测试如下所示
@pytest.fixture
def event():
ee = EventEmitter()
lstr = Listener()
ee.subscribe({"event" : [lstr.operation]})
return lstr, ee
def test_emitter(event):
lstr = event[0]
ee = event[1]
ee.emit("event")
assert lstr.result == 7 # for example
为了测试事件发射器,我需要检查事件传播后监听器的内部状态是否发生了变化。因此,我需要两个对象,我想知道是否有更好的方法来做到这一点(也许使用两个固定装置而不是一个固定装置)因为这对我来说有点难看。
在这种情况下,您可能需要两个灯具。
您可以尝试 @pytest.yield_fixture
,例如:
@pytest.yield_fixture
def event():
...
yield <event_properties>
@pytest.yield_fixture
def listener(event):
...
yield <listener_properties>
通常为了避免tuples
和美化你的代码,你可以将它们重新组合成一个单元作为一个class,这已经为你完成了,使用collections.namedtuple
:
import collections
EventListener = collections.namedtuple('EventListener', 'event listener')
现在修改你的夹具:
@pytest.fixture
def event_listener():
e = EventListener(EventEmitter(), Listener())
e.event.subscribe({'event' : [e.listener.operation]})
return e
现在修改你的测试:
def test_emitter(event_listener):
event_listener.event.emit('event')
assert event_listener.listener.result == 7
您应该在变量中使用名为 iterable unpacking 的 Python 功能。
def test_emitter(event):
lstr, ee = event # unpacking
ee.emit("event")
assert lstr.result == 7
基本上,您将 event[0]
分配给 lstr
,将 event[1]
分配给 ee
。使用此功能是避免使用索引的一种非常优雅的方式。
丢弃
如果你打算在多个测试中使用你的夹具,并且你不需要在每个测试中使用所有值,如果你对使用它们不感兴趣,你也可以丢弃 iterable 的一些元素,如下所示:
l = ['a', 'b', 'c', 'd']
a, b, c, d = l # unpacking all elements
a, _, c, d = l # discarding b
a, _, _, d = l # python 2: discard b and c
a, *_, d = l # python 3: discard b and c
a, _, _, _ = l # python2: discard, b, c and d
a, *_ = l # python3: discard b, c, and d
理论上,你不是字面上的丢弃值,而是in Python_
,so-called“我不在乎”,用于忽略特定值。
如果买不起就随便pytest-cases
plugin as explained in this answer.
对于您的示例,它看起来像:
from pytest_cases import pytest_fixture_plus
@pytest_fixture_plus(unpack_into="lstr,ee")
def event():
ee = EventEmitter()
lstr = Listener()
ee.subscribe({"event" : [lstr.operation]})
return lstr, ee
def test_emitter(lstr, ee):
ee.emit("event")
assert lstr.result == 7 # for example