web-dev-qa-db-ja.com

pytestフィクスチャから複数のオブジェクトを返す

単純なイベントエミッターの実装をテストすることで、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 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

イベントエミッターをテストするには、イベントの伝播後にリスナーの内部状態が変化したかどうかを確認する必要があります。したがって、2つのオブジェクトが必要ですが、これを行うにはもっと良い方法があるのではないかと思います(おそらく、1つではなく2つのフィクスチャを使用する)。これは私にはちょっと醜いように見えるからです。

15
Zallin

うん!この場合、おそらく2つの器具が必要になります。

@pytest.yield_fixtureを次のように試すことができます:

@pytest.yield_fixture
def event():
    ...
    yield <event_properties>

@pytest.yield_fixture
def listener(event):
    ...
    yield <listener_properties>
3
Ederson Badeca

通常、tuplesを回避してコードを美化するために、collections.namedtupleを使用して、それらをクラスとして1つのユニットに結合し直すことができます。

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
6
Sawel

Python iterable unpacking という機能を変数に使用する必要があります。

def test_emitter(event):
    lstr, ee = event # unpacking
    ee.emit("event")
    assert lstr.result == 7

基本的に、event[0]lstrに割り当て、event[1]eeに割り当てます。この機能の使用は、インデックスの使用を回避するための非常に洗練された方法です。

廃棄

複数のテストでフィクスチャを使用する予定で、すべてのテストですべての値が必要なわけではない場合、次のように使用することに興味がなければ、反復可能要素の一部の要素を破棄することもできます。

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

理論的には、文字通り値を破棄しているわけではありませんが、 Pythonの場合_、いわゆる「私は気にしない」は、特定の値を無視するために使用されます。

1
lmiguelvargasf

簡単に タプルフィクスチャを2つの独立したフィクスチャに分割する の余裕がない場合は、-で説明されているように、pytest-casesプラグインを使用して、タプルまたはリストフィクスチャを他のフィクスチャに「アンパック」できます。 この回答

あなたの例では、次のようになります。

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
0
smarie