DY

02 Test unitaire & d'intégration

A partir de maintenant nous nous servirons toujours du même projet pour la suite des TDs.

Et les tests dans tout ça ?

center

Déjà un TD sur les tests unitaires et d'intégrations ? Si tôt dans la découverte de Python et Flask ?

Et oui ! C'est bien beau de parler de TDD mais encore faut il le mettre en place et savoir en faire.

Plutôt que de tout tester à la main de maniére répétitif et fastidieuse, nous allons apprendre à les automatiser pour notre plus grand bonheur 😀.

Pré requis

pytest logo

Pour réaliser les tests unitaires et d'intégrations nous aurons besoin de la librairie ... pytest.

pipenv install pytest
Structure de notre dossier

En reprenant la structure de notre projet vous devriez avoir:

-- app.py
-- Pipfile
-- Pipfile.lock

Nous allons donc créer un répertoire tests à la racine de notre projet qui contiendra nos fichier de tests:

-- tests/
   +-- __init__.py
   +-- test_functions.py
   +-- test_integrations.py
-- app.py
-- Pipfile
-- Pipfile.lock

Premier test unitaire

L'exemple le plus simple pour comprendre le principe des tests unitaires est la fonction de multiplication.

Pour rappel une multiplication est l'opération mathématique permettant d'obtenir le produit de deux facteur (nommés facteur gauche et facteur droite).

Création d'un premier test unitaire

Dans le fichier tests/test_functions.py ajouter le code suivant:

import pytest


def test_multiplication():
    assert 4 == multiplication(2, 2)

Lancez les tests via la commande

pytest --disable-warnings

Normalement vous devriez avoir l'erreur suivante :

$ pytest tests/ --disable-warnings
============================================= test session starts ======================================
tests/test_functions.py F                                                                         [100%]

================================================== FAILURES ============================================
_____________________________________________ test_multiplication ______________________________________

    def test_multiplication():
>       assert 4 == multiplication(2, 2)
E       NameError: name 'multiplication' is not defined

tests/test_functions.py:5: NameError
========================================== 1 failed in 0.03 seconds ====================================

C'est normal ! Nous respectons la philosophie TDD à savoir écrire nos tests d'abord puis vérifier que ceux-ci échouent !

Il convient de créer maintenant notre fonction de multiplication, pour plus de simplicité nous allons créer un module python maths qui contiendra un sous module algebra:

-- tests/
   +-- __init__.py
   +-- test_functions.py
   +-- test_integrations.py
-- maths/
   +-- __init__.py
   +-- algebra.py
-- app.py
-- Pipfile
-- Pipfile.lock

Le code du module math étant au combien complexe (l'erreur de code est volontaire ne la corriger pas):

def multiplication(left_factor, right_factor):
    return left_factor + right_factor

Si on relance notre test (pensez à ajouter un import de la fonction multiplication), celui-ci .. passe ! Mais notre jeu de données n'est pas complet ! Il convient donc d'ajouter une assertion supplémentaire à notre test.

  1. Ajoutez l'assertion dans notre test que le produit de 3 par 7 est 21
  2. Relancez votre test que constatez vous ?
  3. Corrigez le code de votre fonction pour régler ce souci.

Bravo vous venez de faire votre première suite de test unitaire 🎉.

Remarque

Le répertoire tests/ ainsi que le fait de préfixer nos fichier par test_* est une convention qui permet à pytest de charger de manière automatique l'ensemble des tests du répertoire.

À vous de jouer
  1. Créer la suite de tests unitaires pour les opérations arithmétique de base (division, soustraction, addition).

Test d'intégration

Tester nos fonctions c'est bien, utile et indispensable. Toutefois il est tout aussi indispensable de tester le retour de nos pages, nous allons donc voir comment mettre en place des tests d'intégrations.

Création d'un client de test

Dans le fichier test_integrations.py du répertoire tests/

import os
import pytest
from app import app
from flask import url_for


@pytest.fixture
def client():
    app.config['TESTING'] = True
    app.config['SERVER_NAME'] = 'TEST'
    client = app.test_client()
    with app.app_context():
        pass
    app.app_context().push()
    yield client
Notre premier test d'intégration

Ajouter le test d'intégration suivant dans le fichier:

def test_index(client):
    rv = client.get('/')
    assert rv.status_code == 200
    assert b'Hello, World!' in rv.data

Le test d'intégration test_index permet de:

Vous savez désormais tester en intégration une page de votre site web.

Un test un peu plus complexe