pythonunit-testingpytestfixture

Why would a pytest factory as fixture be used over a factory function?


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.


Solution

  • 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!