In the py.test docs it describes declaring factory methods as fixtures, like-so:
@pytest.fixture
def make_foo():
def __make_foo(name):
foo = Foo()
foo.name = name
return foo
return __make_foo
What are the benefits/tradeoffs of doing this over just defining a make_foo function and using that? I don't understand why it is a fixture.
One example might be a session-level fixture, e.g.:
@pytest.fixture(scope="session")
def make_foo():
def __make_foo(name):
foo = Foo()
foo.name = name
return foo
return __make_foo
This way, Pytest will ensure that only one instance of the factory exists for the duration of your tests. This example in particular perhaps doesn't gain much from this, but if the outer function does a lot of processing, such as reading from a file or initialising data structures, then this can save you a lot of time overall.
Actually, the most important advantage is being able to use other fixtures, and make the dependency injection of pytest work for you. The other advantage is allowing you to pass parameters to the factory, which would have to be static in a normal fixture.
Look at this example:
@pytest.fixture
def mocked_server():
with mock.patch('something'):
yield MyServer()
@pytest.fixture
def connected_client(mocked_server):
client = Client()
client.connect_to(mocked_server, local_port=123) # local_port must be static
return client
You could now write a test that gets a connected_client
, but you can't change the port.
What if you need a test with multiple clients? You can't either.
If you now write:
@pytest.fixture
def connect_client(mocked_server):
def __connect(local_port):
client = Client()
client.connect_to(mocked_server, local_port)
return client
return __connect
You get to write tests receiving a connect_client
factory, and call it to get an initialized client in any port, and how many times you want!
If you have many simple factories then you can simplify their creation with decorator:
def factory_fixture(factory):
@pytest.fixture(scope='session')
def maker():
return factory
maker.__name__ = factory.__name__
return maker
@factory_fixture
def make_stuff(foo, bar):
return 'foo' + str(foo + bar)
this is equivalent of
@pytest.fixture(score='session')
def make_stuff():
def make(foo, bar):
return 'foo' + str(foo + bar)
return
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With