Martin Preusse
Martin Preusse

Reputation: 9369

Run pytest test suite against multiple database versions

I build an application that uses a database in the backend. For integration tests, I start the database in Docker and run a test suite with pytest.

I use a session scoped fixture with autouse=True to start the Docker container:

@pytest.fixture(scope='session', autouse=True)
    def run_database():                     
        # setup code skipped ...

        # start container with docker-py
        container.start()

        # yield container to run tests
        yield container

        # stop container afterwards
        container.stop()

I pass the database connection to the test functions with another session scoped fixture:

@pytest.fixture(scope='session')
def connection():
    return Connection(...)

Now I can run a test function:

def test_something(connection):
    result = connection.run(...)
    assert result == 'abc'

However, I would like to run my test functions against multiple different versions of the database.

I could run multiple Docker containers in the run_database() fixture. How can I parametrize my test functions so that they run for two different connection() fixtures?

Upvotes: 3

Views: 1516

Answers (2)

Martin Preusse
Martin Preusse

Reputation: 9369

The answer by @Guy works!

I found another solution for the problem. It is possible to parametrize a fixture. Every test function that uses the fixture will run multiple times: https://docs.pytest.org/en/latest/fixture.html#parametrizing-fixtures

Thus, I parametrized the connection() function:

@pytest.fixture(scope='session', params=['url_1', 'url_2'])
def connection(request):
    yield Connection(url=request.param)

Now every test function that uses the connection fixture runs twice. The advantage is that you do not have to change/adapt/mark the existing test functions.

Upvotes: 1

Guy
Guy

Reputation: 50819

You can send a function that yields connections and pass it with @pytest.mark.parametrize. If you change the the scope of run_database() to class it will run for every test

def data_provider():
    connections = [Connection(1), Connection(2), Connection(3)]
    for connection in connections:
        yield connection


@pytest.fixture(scope='class', autouse=True)
def run_database():
    container.start()
    yield container
    container.stop()


@pytest.mark.parametrize('connection', data_provider())
@pytest.mark.testing
def test_something(connection):
    result = connection.run()
    assert result == 'abc'

If you add @pytest.mark.parametrize('connection', data_provider()) to run_database() the connection will be passed to there as well.

Upvotes: 0

Related Questions