Question

Je suis dans un projet où nous commençons à refactoriser une base de code massive. Un problème qui a immédiatement surgi est que chaque fichier importe beaucoup d'autres fichiers. Comment puis-je me moquer de cela de manière élégante dans mon test unitaire sans modifier le code afin de pouvoir commencer à écrire des tests unitaires?

Par exemple: le fichier avec les fonctions que je veux tester importe dix autres fichiers qui font partie de notre logiciel et non de la bibliothèque principale de Python.

Je veux pouvoir exécuter les tests unitaires aussi séparément que possible et pour l'instant je ne ferai que tester des fonctions qui ne dépendent pas des éléments des fichiers en cours d'importation.

Merci pour toutes les réponses.

Je ne savais pas vraiment ce que je voulais faire depuis le début, mais maintenant je pense que je le sais.

Le problème était que certaines importations n'étaient possibles que lorsque l'application entière était en cours d'exécution en raison d'une magie automatique tierce. Je devais donc faire quelques stubs pour ces modules dans un répertoire que j’avais signalé avec sys.path

Je peux maintenant importer le fichier contenant les fonctions pour lesquelles je veux écrire des tests dans mon fichier de tests unitaires sans vous plaindre des modules manquants.

Était-ce utile?

La solution

Si vous souhaitez importer un module tout en évitant de rien importer, vous pouvez remplacer la fonction intégrée __ import __ .

Par exemple, utilisez cette classe:

class ImportWrapper(object):
    def __init__(self, real_import):
        self.real_import = real_import

    def wrapper(self, wantedModules):
        def inner(moduleName, *args, **kwargs):
            if moduleName in wantedModules:
                print "IMPORTING MODULE", moduleName
                self.real_import(*args, **kwargs)
            else:
                print "NOT IMPORTING MODULE", moduleName
        return inner

    def mock_import(self, moduleName, wantedModules):
        __builtins__.__import__ = self.wrapper(wantedModules)
        try:
            __import__(moduleName, globals(), locals(), [], -1)
        finally:
            __builtins__.__import__ = self.real_import

Et dans votre code de test, au lieu d'écrire importer myModule , écrivez:

wrapper = ImportWrapper(__import__)
wrapper.mock_import('myModule', [])

Le deuxième argument de importation_importée est une liste de noms de modules que vous faites importer dans le module interne.

Cet exemple peut être modifié par ex. importer un autre module que souhaité au lieu de ne pas l'importer ou même de se moquer de l'objet module avec votre propre objet personnalisé.

Autres conseils

Si vous voulez vraiment vous amuser avec le mécanisme d'importation Python, consultez le < code> ihooks . Il fournit des outils pour modifier le comportement de la fonction intégrée __ import __ . Mais votre question ne dit pas pourquoi vous devez faire cela.

"Importe beaucoup d'autres fichiers" Importe beaucoup d'autres fichiers qui font partie de votre base de code personnalisée? Ou importe beaucoup d'autres fichiers qui font partie de la distribution Python? Ou importe-t-il beaucoup d'autres fichiers de projet open source?

Si vos importations ne fonctionnent pas, vous avez un " simple " PYTHONPAT Problème H. Obtenez tous vos différents répertoires de projet sur un PYTHONPATH que vous pouvez utiliser pour les tests. Nous avons un chemin assez complexe, dans Windows nous le gérons comme ceci

@set Part1=c:\blah\blah\blah
@set Part2=c:\some\other\path
@set that=g:\shared\stuff
set PYTHONPATH=%part1%;%part2%;%that%

Nous gardons chaque élément du chemin séparé pour pouvoir (a) savoir d'où viennent les choses et (b) pouvoir gérer les changements lorsque nous les déplaçons.

Etant donné que la recherche PYTHONPATH est effectuée dans l'ordre, nous pouvons contrôler ce qui sera utilisé en ajustant l'ordre du chemin.

Une fois que vous avez "tout", cela devient une question de confiance.

Soit

  • vous faites confiance à quelque chose (c'est-à-dire à la base de code Python) et importez-le simplement.

Ou

  • Vous ne faites pas confiance à quelque chose (c'est-à-dire votre propre code) et vous

    1. testez-le séparément et
    2. le simulacre pour des tests autonomes.

Souhaitez-vous tester les bibliothèques Python? Si oui, vous avez beaucoup de travail. Sinon, vous devriez peut-être simplement vous moquer des choses que vous allez réellement tester.

Aucune manipulation difficile n'est nécessaire si vous souhaitez une solution rapide avant vos tests unitaires.

Si les tests unitaires se trouvent dans le même fichier que le code que vous souhaitez tester, supprimez simplement le module non souhaité du dictionnaire globals () .

Voici un exemple assez long: supposons que vous ayez un module impp.py avec le contenu suivant:

value = 5

Vous pouvez maintenant écrire dans votre fichier de test:

>>> import impp
>>> print globals().keys()
>>> def printVal():
>>>     print impp.value
['printVal', '__builtins__', '__file__', 'impp', '__name__', '__doc__']

Notez que impp fait partie des globals, car il a été importé. L'appel de la fonction printVal utilisant le module impp fonctionne toujours:

>>> printVal()
5

Mais maintenant, si vous supprimez la clé impp de globals () ...

>>> del globals()['impp']
>>> print globals().keys()
['printVal', '__builtins__', '__file__', '__name__', '__doc__']

... et essayez d'appeler printVal () , vous obtiendrez:

>>> printVal()
Traceback (most recent call last):
  File "test_imp.py", line 13, in <module>
    printVal()
  File "test_imp.py", line 5, in printVal
    print impp.value
NameError: global name 'impp' is not defined

... ce qui est probablement exactement ce que vous essayez d'atteindre.

Pour l'utiliser dans vos tests unitaires, vous pouvez supprimer les globales juste avant d'exécuter la suite de tests, par exemple. dans __ main __ :

if __name__ == '__main__':
    del globals()['impp']
    unittest.main()

Dans votre commentaire ci-dessus , vous dites vouloir convaincre python que certains modules ont déjà été importés. Cela semble toujours être un objectif étrange, mais si c'est vraiment ce que vous voulez faire, vous pouvez en principe vous faufiler derrière le mécanisme d'importation et modifier sys.modules . Je ne sais pas comment cela fonctionnerait pour les importations de packages, mais cela devrait convenir pour les importations absolues.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top