Aller au contenu principal

Lancer des tests unitaires avec Django

· 4 minutes de lecture
Stéphane ROBERT
Consultant DevOps

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.

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 :

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:

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 :

docker-compose down

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

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 :

  • On utilise un des services fournis par gitlab et en l'occurrence ici une bdd postgresql. Gitlab met à disposition aussi des services mysql et redis.

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 :