Taku
Taku

Reputation: 622

Pytest - create an object shared by multiple tests

In my functional tests I need to create an object (which relates to a virtual server - not mocked one) which will be shared by a set of tests. Server is created with some py.test fixtures used (environment, host etc) to specify on which environment it's supposed to be set up - tests run on multiple different environments. My current approach is ugly, like this abstract example:

# [host, env, dns are fixtures, defined in conftest.py and passed from
# commandline args - py.test recognizes them so they can be changed
# each time the test is invoked from CLI]

@pytest.mark.parametrize(parameters_from_parametrize)

def test_something(host, env, dns):
    server = Server(host,env, dns, random_name, random_passwd)
    server.create()
    server.do_stuff(parameters_from_parametrize)
    check_stuff()
    server.delete()

But this creates a new server for each set of parameters_from_parametrize. Is there a way to create one server, using the fixtures, and then run that server?

as in, for example:

server = Server(host,env, dns, random_name, random_passwd)
server.create()

@pytest.mark.parametrize(parameters_from_parametrize)

def test_something(server):
    server.do_stuff(parameters_from_parametrize)
    check_stuff()

server.delete()

This way server would only be created once. Example above doesn't work, since fixtures cannot be used before test functions (and the code outside test functions won't share the scope with them), so adding server outside of test function fails. I tried setup and teardown, but I cannot get it to work with fixtures.

Is there a way to do it? I thought I'd be able to do it using setup/teardown, or by creating a test class, but I failed.

I hope this is not an extremely noobish question, but it probably is.

Upvotes: 13

Views: 10528

Answers (1)

bereal
bereal

Reputation: 34252

That's what fixtures are for:

@pytest.fixture(scope='session')  # one server to rule'em all
def server():
    server = Server(host, env, dns, random_name, random_passwd)
    server.create()
    return server

def test_something(server, ...):
    # test logic

This can also be improved to shutdown the server after the tests complete:

@pytest.yield_fixture(scope='session')
def server():
    server = Server(host,env, dns, random_name, random_passwd)
    server.create()
    yield server
    server.delete()

In either case pytest will handle the server creation according to the defined scope and provide the server argument to all test functions having it. That way, the server is created only once per testing session regardless of how many tests are using it, and how they are parameterised.

Upvotes: 19

Related Questions