Aller au contenu

Lancer des tests unitaires avec Django

En tant que devops je dois mettre en place ce qu’il faut pour lancer des tests unitaires et ce sur une application écrite en python et utilisant le framework Django. Cela doit me permettre de faire tourner ces tests dans un pipeline gitlab et d’avoir le rapport du taux de couverture de code en sortie.

Mais voila je ne veux pas installer postgresql dans ma VM Linux ! Donc voyons comment utiliser docker et docker-compose.

Mise en place d’une application Django

Le plus simple est de suivre le tutoriel disponible en français sur le site de Django

Mais non, voici le lien vers le repo contenant le résultat. Je me suis arrêté après la mise en place des tests unitaires.

Terminal window
git clone git@gitlab.com:Bob74/tuto-django-test-docker.git

Installations des outils sur mon linux

Il faut bien que dans votre vm vous ayez installé Docker, python devant l’être deja. Vous pouvez créer un environnement virtuel avec pyenv.

Pour installer docker-compose dans une fenêtre shell tapez les commandes suivantes :

Terminal window
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose --version
docker-compose version 1.29.2, build 5becea4c

Maintenant créons le Dockerfile qui nous permettra de lancer les tests unitaires. Pour cela on créé un fichier Dockerfile à la racine du projet contenant ces lignes:

FROM python:3.9-slim
ENV PYTHONUNBUFFERED=1
COPY . /code/
WORKDIR /code
RUN pip install -r requirements.txt

Vous remarquerez qu’il n’y a rien de bien compliqué. Le contenu du fichier requirements.txt

coverage==6.0.2
Django==3.2.8
psycopg2-binary==2.9.1

Maintenant passons à l’écriture du fichier docker-compose.yml :

version: '3'
services:
app:
build: ./
command: bash -c "while !</dev/tcp/postgres/5432; do sleep 1; done; coverage run manage.py test polls --parallel=4 && coverage report"
volumes:
- "./reports/:/code/reports"
depends_on:
- postgres
environment:
POSTGRES_DB: db_mysite
POSTGRES_USER: 'user_mysite'
POSTGRES_PASSWORD: 'pass_mysite'
DATABASE_URL: "postgresql://user_mysite:pass_mysite@postgres:5432/db_mysite"
postgres:
restart: always
image: postgres:10-alpine
environment:
POSTGRES_USER: user_mysite
POSTGRES_PASSWORD: pass_mysite
POSTGRES_DB: db_mysite

Quelques explications :

  • La stack est composée de deux containers:
    • un qui contient la bdd, postgres, initialisé avec les paramètres USER, PASSWORD et DB
    • un autre, app, qui servira à lancer les tests avec l’image créé précédemment.

La commande lancée permet d’attendre que la bdd soit disponible pour s’exécuter.Elle attend que le port 5432 soit up sur le container postgres. Une fois disponible, les tests sont lancés et le rapport de couverture de code est généré.

Voyons comment lancer les tests:

Terminal window
docker-compose run app
Creating mysite_app_run ... done
Creating test database for alias 'default'...
Cloning test database for alias 'default'...
Cloning test database for alias 'default'...
System check identified no issues (0 silenced).
.......
----------------------------------------------------------------------
Ran 7 tests in 0.097s
OK
Destroying test database for alias 'default'...
Destroying test database for alias 'default'...
Destroying test database for alias 'default'...
Name Stmts Miss Cover
------------------------------------------------------
manage.py 12 2 83%
mysite/__init__.py 0 0 100%
mysite/settings.py 19 0 100%
mysite/urls.py 3 0 100%
polls/__init__.py 0 0 100%
polls/admin.py 3 0 100%
polls/apps.py 4 0 100%
polls/migrations/0001_initial.py 6 0 100%
polls/migrations/__init__.py 0 0 100%
polls/models.py 17 4 76%
polls/tests.py 42 27 36%
polls/urls.py 4 0 100%
polls/views.py 26 9 65%
------------------------------------------------------
TOTAL 136 42 69%

Et oui rien de plus simple! Attention le container postgresql continuera de vivre sa VIE. Pour l’arrêter il suffit de taper la commande suivante :

Terminal window
docker-compose down

Si vous avez fait des modifications sur le Dockerfile il faudra relancer le build de celui-ci :

Terminal window
docker-compose build app

Intégrer les tests dans un pipeline gitelab

Il suffit d’écrire le fichier .gitlab-ci suivant en ayant au préalable stocker

stages:
- test
services:
- postgres:12.2-alpine
unit-test-job:
image: python:3.9-slim
stage: test
variables:
POSTGRES_DB: postgres
POSTGRES_USER: 'user_mysite'
POSTGRES_PASSWORD: 'pass_mysite'
POSTGRES_HOST_AUTH_METHOD: trust
DATABASE_URL: "postgresql://user_mysite:pass_mysite@postgres:5432/db_mysite"
script:
- pip install -r requirements.txt
- coverage run manage.py test --configuration=Test --parallel=2
- coverage report
- mkdir coverage-reports
- coverage xml -o coverage-reports/coverage-report.xml
coverage: "/TOTAL.+ ([0-9]{1,3}%)/"
artifacts:
paths:
- coverage-reports/coverage-report.xml
expire_in: 1d

Quelques explications :

La suite on peut ajouter :

  • un stage de lint un lançant un job flake8
  • un autre pour lancer un scan pour envoyer un rapport dans sonarqube
  • un autre pour générer un package et le stocker dans le package registry de gitlab.

Petite cerise sur le gâteau. Voici comment créer le badge affichant le coverage sur la page du projet.

Allez dans le menu Settings -> General -> Badges

Remplir comme indiqué ci dessous :

badge coverage