Les Crash-Devs d'un Passionné

Mocker un fichier pour vos tests

/Catégorie/python

Temps de lecture : 3 minutes

Lors de la réalisation de test unitaire et lorsqu'il est nécessaire de communiquer avec le système de fichier il est nécessaire de simuler (j'utiliserais aussi le mot

mocker
) cette communication IO


Pourquoi simuler un fichier ?

  • dans un test unitaire où l'on veut tester du fonctionnel la lecture du fichier n'est pas un point que l'on veut éprouver (contrairement à un test d'intégration) cette source de données ne nous intéresse pas contrairement à son contenu
  • cela améliore l'exécution des TU car pas de communication réseau
  • permet de maitriser le contenu de la donnée


Mocker des données représente une source de risque car il faut mettre à jour le contenu du fichier simulé si la partie du code qui la génère évolue.

Pour faire cela nous allons nous reposer sur la librairie standard

unittest.mock
qui propose la fonction
patch()
qui sera utilisée dans notre exemple en tant que décorateur mais on pourrait aussi bien l'utiliser en context manager.

Cette fonction va se connecter sur le module désiré précisé en 1er paramètre, ici la fonction standard

open

Le paramètre
read_data
permet quant à lui d'indiquer le contenu à retourner : le contenu du fichier que l'on simule.

clipboard
Copier le code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from unittest.mock import patch

text_file_data = '\n'.join([ "email,start_hour,end_hour","me@rigaudie.fr,10:00:00,12:00:00"])

@patch("builtins.open", read_data=text_file_data)
def test_sunrise_under_sunset(magic_mock_file):
    with open("file_not_exist.txt") as f:
        for i, line in enumerate(f.readlines()):
            assert len(line.split(",")) == 3
            
            assert line.rstrip() == text_file_data.split("\n")[i]

Le code ci-dessus ouvre un fichier inexistant mais comme le mock ne va pas chercher le fichier réel mais simuler son contenu, cela ne pose pas de soucis d'accès à ce fichier.
Aussi vous pouvez mettre n'importe quel nom de fichier cela restera opérationnel : je vous conseille de mettre le nom que votre programme attend pour rester compréhensible

On remarque que la fonction

test_sunrise_under_sunset
prend un paramètre. Ce paramètre
magic_mock_file
(dont j'ai inventé le nom, vous pouvez le nommer comme vous souhaitez) correspond au retour du décorateur
patch
et qui vaut un
MagicMock

Comme les fixtures sur
pytest
, si on ne le précise pas il ne sera pas injecter dans la fonction de test

MagicMock
est une sous classe de
Mock
et qui va implémenter la plupart des méthodes magiques à votre place (les méthodes magiques sont les fonctions avec 2 underscores avant et après le nom de la fonction, ce sont des méthodes internes et propres à python) ici ce sont __enter__() et __exit__()

Pour tester cette logique vous avez juste à installer
pytest
et executer les tests avec la commande
pytest


Un bout de code pas très compliqué mais qui vous rendra de nombreux services