91 votes

Comment tester ou se moquer du contenu "if __name__ == '__main__'"

Disons que j'ai un module avec les éléments suivants :

 def main():
    pass

if __name__ == "__main__":
    main()

Je veux écrire un test unitaire pour la moitié inférieure (j'aimerais atteindre une couverture de 100%). J'ai découvert le module intégré runpy qui exécute le __name__ , mais je ne sais pas comment se moquer ou vérifier que la fonction main() est appelée.

Voilà ce que j'ai essayé jusqu'à présent :

 import runpy
import mock

@mock.patch('foobar.main')
def test_main(self, main):
    runpy.run_module('foobar', run_name='__main__')
    main.assert_called_once_with()

15voto

David Heffernan Points 292687

Vous pouvez le faire en utilisant le imp plutôt que l'instruction import Le problème avec l' import est que le test pour '__main__' s'exécute dans le cadre de l'instruction import avant que vous n'ayez la possibilité d'attribuer à runpy.__name__ .

Par exemple, vous pouvez utiliser imp.load_source() comme ceci :

 import imp
runpy = imp.load_source('__main__', '/path/to/runpy.py')

Le premier paramètre est affecté à __name__ du module importé.

9voto

Samuel Marks Points 21

Solution Python3 :

 import os
from importlib.machinery import SourceFileLoader
from importlib.util import spec_from_loader, module_from_spec
from importlib import reload
from unittest import TestCase
from unittest.mock import MagicMock, patch
    

class TestIfNameEqMain(TestCase):
    def test_name_eq_main(self):
        loader = SourceFileLoader('__main__',
                                  os.path.join(os.path.dirname(os.path.dirname(__file__)),
                                               '__main__.py'))
        with self.assertRaises(SystemExit) as e:
            loader.exec_module(module_from_spec(spec_from_loader(loader.name, loader)))

En utilisant la solution alternative de définir votre propre petite fonction :

 # module.py
def main():
    if __name__ == '__main__':
        return 'sweet'
    return 'child of mine'

Vous pouvez tester avec :

 # Override the `__name__` value in your module to '__main__'
with patch('module_name.__name__', '__main__'):
    import module_name
    self.assertEqual(module_name.main(), 'sweet')

with patch('module_name.__name__', 'anything else'):
    reload(module_name)
    del module_name
    import module_name
    self.assertEqual(module_name.main(), 'child of mine')

3voto

Mr Fooz Points 21092

Une approche consiste à exécuter les modules en tant que scripts (par exemple, os.system(...)) et à comparer leur sortie stdout et stderr aux valeurs attendues.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X