2
votes

Test unitaire de "renommer les fichiers" en Python

Supposons que j'ai la fonction suivante et que j'ai besoin de la tester unitaire:

def move_files_to(files, path):
for file in files:
    os.rename(file, path + "/" + file)

mes réflexions sur ce sujet:

Se moquer de os.rename ne mènerait à aucun résultat , d'un autre côté, avoir des fichiers et les renommer reviendrait à "faire des E / S", ce qui devrait être évité dans les tests unitaires. S'il vous plait corrigez moi si je me trompe. Les tests ont-ils un sens ici?


5 commentaires

Vous pouvez créer un fichier factice, le déplacer, faire un os.path.exists pour vous assurer qu'il a été déplacé puis le supprimer, toujours IO mais parfois ces tests peuvent être utiles pour attraper les exceptions que vous ne pouvez pas attraper avec monkeypatching.


Si vous vous moquez de os.rename () , vous pouvez toujours affirmer qu'il a été appelé avec les paramètres attendus. En général, je ne pense pas que ce type de test offre beaucoup de valeur, car vous devez essentiellement réimplémenter la fonction pour affirmer qu'elle fait les bons appels à os.rename () , mais cela aide toujours à assurez-vous que la fonction ne contient aucun identifiant mal saisi, etc.


@SvenMarnach pourquoi ne postez-vous pas ceci comme réponse? Pour moi, cela semble être la solution la plus raisonnable


@SvenMarnach Je ferais également une vérification de chemin pour m'assurer que les deux chemins fournis à os.rename sont valides.


@David Je ne pense tout simplement pas qu'il y ait une «bonne» réponse ici. Dans de nombreux cas, je ne testerais pas personnellement cette fonction. C'est très simple, pylint détectera la plupart des fautes de frappe, et il existe peut-être un test d'intégration qui couvre cette fonction d'une manière ou d'une autre. Mais tout dépend du contexte, de la philosophie de test du projet et de vos préférences personnelles, j'ai donc préféré écrire ceci en commentaire.


3 Réponses :


3
votes

Ma recommandation serait de

créer un DirectoryTestCase (unittest.TestCase) avec

  1. une configuration qui i) supprime un répertoire (non suivi) s'il existe (par exemple _tests sous tests / ) ii) crée un répertoire vide et iii) copie (tester) les fichiers.
  2. un démontage qui supprime le répertoire

Deuxièmement, créez les tests sous ce cas de test. Vous pouvez tester le déplacement vers le même répertoire (renommer), vers un nouveau répertoire (sous le répertoire de test, doit-il créer s'il n'existe pas ou échouer?) Déplacer un lien symbolique, etc., le tout sous l'encapsulation du répertoire existant.

Si vous voulez que les tests s'exécutent en parallèle, donnez au répertoire un nom unique (aléatoire mais valide).

Exemple de code:

import unittest
import shutil
import os
import string
import random


class DirectoryTestCase(unittest.TestCase):
    test_files = ['file.txt']

    def setUp(self) -> None:
        unique_string = ''.join(random.choices(string.digits, k=10))

        self.path = os.path.join(os.path.dirname(__file__), '_temp' + unique_string)

        shutil.rmtree(self.path, ignore_errors=True)

        os.makedirs(self.path, exist_ok=True)

        for file in self.test_files:
            shutil.copy(file, self.path)

    def tearDown(self) -> None:
        shutil.rmtree(self.path, ignore_errors=True)

    def test_basic(self):
        # validate the existence of the file, not an actual test.
        self.assertTrue(os.path.exists(os.path.join(self.path, 'file.txt')))


0 commentaires

0
votes
  1. puisqu'il est difficile de simuler le module OS en python, vous pouvez ignorer pour écrire unitest

  2. Mais le test unitaire signifie valider votre méthode unique avec quelques scénarios possibles, donc si vous pensez que cela doit valider à tout moment. alors un test unitaire est indispensable.


0 commentaires

2
votes

Il n'est pas nécessaire de tester os.rename , mais votre code doit être testé. Dans votre cas particulier, le moyen le plus simple est de patcher os.rename:

from unittest.mock import patch

def test_move_files():
    files = ['a.txt', 'b.txt']
    path = 'old'
    expected = [(('a.txt', 'old/a.txt'),),
                (('b.txt', 'old/b.txt'),)]
    with patch('os.rename') as rename:
        move_files_to(files, path)
        assert rename.call_args_list == expected


0 commentaires