Pytest-mock. How to mock your database connection.

Mariusz Raczynski
2 min readOct 23, 2017

--

Northern mockingbird

I like tests, you like tests, everybody likes the tests! However setting them up can sometimes be a painful, hair-pulling experience.

Our back-end application is a simple Restful uWSGI app, which exposes endpoints and returns JSON for the front-end app. For local development the app is fully dockerized (docker-compose) and contains three containers ( uWSGI, Redis, PosgreSQL ). However once in production we have separate instance for PostgreSQL, Redis and only uWISG service is running inside a docker container.

Our CI/CD involves a step during which the tests are being run. Half of the tests ( the functional ones ) are done against a running uWSGI app thus checking we have not broken any endpoints the front-end app needs. The other half ( unit tests ) are run by tox on code “outside” of the container. But how do we test the portions of code which interacts with the database?

In order to take an advantage of the fact that we have an instance of PosgreSQL database sitting in one of the containers we will use mock.patch to swap database connection settings and point our “outside” code to the right container.

The minimal example code might look like this:

@pytest.fixture(autouse=True)                       
def _mock_db_connection(mocker, db_connection):
mocker.patch('db.database.dbc', db_connection)

@pytest.fixture(autouse=True) will make sure all tests will use mocked dbc object.

if not os.environ.get('TEST'):
dbc = psycopg2.connect(**db_settings)
dbc.autocommit = True
else:
dbc = None

If we are in ‘TEST’ mode the database settings have to return a dummy object, which then gets overridden by mock. If we don’t do this the psyconpg2.connect method will just error out and we won’t be able to mock anything.

We use the same strategy to mock our Redis connection and celery broker connection. Here are some more docs on the wonder of mocking.

Happy mocking ;)

--

--