Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning multiple objects from a pytest fixture

Tags:

I am learning how to use pytest by testing a simple event emitter implementation.

Basically, it looks like this

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 

For convenience, I created a Listener class that is used in tests

class Listener():     def __init__(self):         ...     def operation(self):         # actual listener 

Currently, test looks the following way

@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 

In order to test event emitter, I need to check whether the inner state of the listener has changed after event propagation. Thus, I need two objects and I wonder if there is a better way to do this (maybe use two fixtures instead of one somehow) because this looks kinda ugly to me.

like image 319
Zallin Avatar asked May 20 '16 16:05

Zallin


2 Answers

Usually in order to avoid tuples and beautify your code, you can join them back together to one unit as a class, which has been done for you, using collections.namedtuple:

import collections EventListener = collections.namedtuple('EventListener', 'event listener') 

Now modify your fixture:

@pytest.fixture def event_listener():  e = EventListener(EventEmitter(), Listener())  e.event.subscribe({'event' : [e.listener.operation]})  return e 

Now modify your test:

def test_emitter(event_listener):  event_listener.event.emit('event')  assert event_listener.listener.result == 7 
like image 165
Sawel Avatar answered Sep 18 '22 01:09

Sawel


You should use a Python feature called iterable unpacking into variables.

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

Basically, you are assigning event[0] to lstr, and event[1] to ee. Using this feature is a very elegant way to avoid using indexes.

Discarding

In case you are going to use your fixture in mutiple tests, and you don't need all values in every test, you can also discard some elements of the iterable if you are not interested in using them as follows:

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 theory, you are not literally discarding the values, but in Python _, so-called “I don’t care”, is used for ignoring the specific values.

like image 40
lmiguelvargasf Avatar answered Sep 17 '22 01:09

lmiguelvargasf