Test Driven Development with PyTest, Django and Docker — Set up

Kakar Nyori
4 min readJul 27, 2021

--

Test-driven development is going through the process of writing the test first, then writing the required code to pass the test. Finally, if need be, refactor the code. So it is a cycle of Red — Green — Refactor.

  1. Red : Since we are writing our test for the provided specifications, we will get errors as we still don’t have the code to test for.
  2. Green : After we get errors from running our test, we need to write the minimum code required to pass our test.
  3. Refactor : This is optional. If you need, you can update and optimize your code.

We will create a simple Todo app. I will be working on VSCode, and along the way let you know how set up VSCode for our project.

Define our project’s components

Create a directory for your project and open it on your code editor.

mkdir docker-django-todos-project # root directory of our projectcd docker-django-todos-projectcode .   # open in vscode

Now create a Dockerfile in your root (project’s) directory and add the following:

# syntax=docker/dockerfile:1
FROM python:3
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/

Create a requirements.txt file (root directory) for Django project’s dependencies:

Django>=3.0,<4.0
psycopg2-binary>=2.8
djangorestframework
pytest
pytest-django
git+git://github.com/mverteuil/pytest-ipdb.git
pytest-cov
mixer
mock

Finally, let’s create a docker-compose.yml file in the root directory and add the following:

version: "3.9"

services:
db:
image: postgres
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
db:
condition: service_healthy

Create a Django project

From the root (project’s) directory, create the Django project by running the docker-compose run command as follows:

docker-compose run web django-admin startproject todos_project .

Notice the . at the end of the command to start the project with the project name. It starts the project in the current directory without creating a new directory for the project.

Connect the database

In your project directory, edit the todos_project/settings.py file, and replace the DATABASES = ... with the following:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgres',
'USER': 'postgres',
'PASSWORD': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}

Let’s see if everything is working by running docker-compose up from the root directory:

docker-compose up

If you see this:

then open your browser and go to the localhost:8000 and you should see this wonderful page!

VSCode settings

We will use our project’s docker container as the python interpreter, and our VSCode terminal can access the container as well.

If you started the containers from the VsCode terminal, then press ctrl + c and stop the container. Again start the containers in detached mode, with -d flag:

docker-compose up -d

Once the container is running in the background, open the command palette by pressing ctrl + shift + p

Search “remote containers” and select Remote-Containers: Attach to Running Container and then select your docker Django web container docker-todos-project-django_web

Note: The docker container must be running for this to work.

This will open a new VsCode window. You can now close the previous VSCode.

  1. On the Explorer, click on the open folder and select or enter /code and enter.
  2. Install the Python (by Microsoft) extension in the container.

Introducing PyTest

Create test_settings.py file inside todos_project/ and add the following:

from .settings import *DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

Create pytest.ini file in the root directory and add the following:

[pytest]
DJANGO_SETTINGS_MODULE = todos_project.test_settings
; # -- recommended but optional:
; python_files = tests.py test_*.py *_tests.py
addopts = --nomigrations --cov=. --cov-report=html

Create a .coveragerc file in the root directory for the project’s Pytest coverage report and add the following:

[run]
omit =
*apps.py,
*migrations/*.py,
*settings*.py,
*tests/*.py,
*urls.py,
*wsgi.py,
*asgi.py,
*test.py,
manage.py

Let’s check if Pytest is working by running:

pytest

And you should see this:

Running pytest will also create a htmlcov directory in your project’s root directory. You can check your coverage report by opening htmlcov/index.html in your browser.

The final project structure should look something like this:

- data
- - db
- - - ...
- - - ...
- db.sqlite3
- docker-compose.yml
- Dockerfile
- htmlcov
- - index.html
- - ...
- - ...
- manage.py
- pytest.ini
- requirements.txt
- todos_project
- - asgi.py
- - settings.py
- - test_settings.py
- - urls.py
- - wsgi.py
- - __init__.py

Now that all the required work needed for PyTest is done, we will continue with Test Driven Development and a Django App in the next part.

If you want, you can check out the repo.

See you on the other side!

--

--

Kakar Nyori
Kakar Nyori

Responses (1)