Setup a Testing Environment with Docker and Pytest-Django: PostreSQL schema issue
Tags: django, python, docker, sql
Published: 2022-06-16 20:53:02

I am working on a fintech project where there are a lot of products. The whole project is built on Django, and products are just applications with their own logic, but all rely on a core application. 
This core application actually handles stuff like authentication, organization creation, and wallet transactions because the same logic is repeated on the other application. This actually pushed me to mirror the same structure on the database by using schema. 
Each application on the project has its own schema. 
But things are a little tricky when it comes to testing with pytest. 
Also, note that I am using Docker and running the tests using Docker. 

## The issue

It isn't straightforward to create the schema in the testing database using Pytest. As I am using the same database container for the dev environment and testing, a testing database is created; naturally, it's great. 
As I already have a schema created for the dev database, and there is no way to generate a schema for a precise database using SQL statements in Postgres, my tests have constantly been failing. 

```
return self.cursor.execute(sql, params)
E               django.db.utils.ProgrammingError: relation "core.user" does not exist
E               LINE 1: INSERT INTO "core"."user" ("password", "last_login", "public...

```
Not really interesting, right? Here's my solution. 

## Solution

A simple solution is adding a testing database container to my `docker-compose.dev.yaml` file.

```yaml
  db_test:
    container_name: test_optimus_db
    image: postgres:14.3-alpine
    environment:
      DATABASE_NAME: test_optimusdb
      DATABASE_USER: test_optimus
      DATABASE_PASSWORD: Qinsjhgvv45LJSD
      DATABASE_HOST: test_optimus_db
      DATABASE_PORT: 5432
      POSTGRES_USER: test_optimus
      POSTGRES_PASSWORD: Qinsjhgvv45LJSD
      POSTGRES_DB: test_optimusdb
    volumes:
      - postgres_data_test:/var/lib/postgresql/data/
      - ./db/db_test_init.sql:/docker-entrypoint-initdb.d/1-init.sql
```

The `db_test_init.sql` file looks like this.

```SQL
GRANT ALL PRIVILEGES ON DATABASE test_optimusdb TO test_optimus;

CREATE SCHEMA IF NOT EXISTS core AUTHORIZATION test_optimus;
CREATE SCHEMA IF NOT EXISTS optimus AUTHORIZATION test_optimus;
```

With the init SQL script ready, we just need to add this function to the `conftest.py` file configuration.

```python
import pytest

from django.conf import settings


@pytest.fixture(scope="session")
def django_db_setup():
    settings.DATABASES["default"] = {
        "ENGINE": "django.db.backends.postgresql",
        "HOST": "test_optimus_db",
        "NAME": "test_optimusdb",
        "PASSWORD": "Qinsjhgvv45LJSD",
        "USER": "test_optimus",
        "PORT": 5432,
    }
```

And we are done. Running the tests now will pass. 

```python
docker-compose -f docker-compose.dev.yml exec -T web pytest -s -v --traceconfig
```

And voilà. Even if this solution works and gives much control over the testing environment, I am still looking for automated solutions. So feel free to add comments if you have already faced this issue, and let's discuss it.