104 votes

Comment définir sys.argv pour que je puisse le tester unitairement?

Je voudrais définir

sys.argv

afin de pouvoir tester unitairement en passant différentes combinaisons. Ce qui suit ne fonctionne pas:

#!/usr/bin/env python
import argparse, sys

def test_parse_args():
    global sys.argv
    sys.argv = ["prog", "-f", "/home/fenton/project/setup.py"]
    setup = get_setup_file()
    assert setup == "/home/fenton/project/setup.py"

def get_setup_file():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f')
    args = parser.parse_args()
    return args.file

if __name__ == '__main__':
    test_parse_args()

Ensuite, exécutez le fichier:

pscripts % ./test.py                                                                                           
  File "./test.py", line 4
    global sys.argv
              ^
SyntaxError: invalid syntax
pscripts %

1voto

progfan Points 1067

J'ai réussi en créant un gestionnaire d'exécution qui définirait les arguments de mon choix et les supprimerait à la sortie :

import sys    

class add_resume_flag(object):
    def __enter__(self):
        sys.argv.append('--resume')

    def __exit__(self, typ, value, traceback):
        sys.argv = [arg for arg in sys.argv if arg != '--resume']

class MyTestClass(unittest.TestCase):

    def test_something(self):
        with add_resume_flag():
            ...

0voto

ftravers Points 1016

Normalement, vous aurez des arguments de commande. Vous devez les tester. Voici comment les tester unitairement.

  • Supposez que le programme puisse être exécuté comme suit : % myprogram -f setup.py

  • Nous créons une liste pour imiter ce comportement. Voir la ligne (4)

  • Ensuite, notre méthode qui analyse les arguments prend un tableau comme argument qui est par défaut None. Voir la ligne (7)

  • Ensuite, à la ligne (11), nous passons ceci à parse_args, qui utilise le tableau s'il n'est pas None. S'il est None, il se contente d'utiliser sys.argv par défaut.

    1: #!/usr/bin/env python
    2: import argparse
    3: def test\_parse\_args():
    4:     my\_argv = \["-f", "setup.py"\]
    5:     setup = get\_setup\_file(my\_argv)
    6:     assert setup == "setup.py"
    7: def get\_setup\_file(argv=None):
    8:     parser = argparse.ArgumentParser()
    9:     parser.add\_argument('-f')
    10:     # si argv est 'None', alors il sera par défaut à 'sys.argv'
    11:     args = parser.parse\_args(argv) 
    12:     return args.f
    13: if \_\_name\_\_ == '\_\_main\_\_':
    14:     test\_parse\_args()

0voto

Fred Mitchell Points 1068

Très bonne question.

Le truc pour mettre en place des tests unitaires consiste surtout à les rendre répétables. Cela signifie que vous devez éliminer les variables, de sorte que les tests soient répétables. Par exemple, si vous testez une fonction qui doit fonctionner correctement en fonction de la date actuelle, forcez-la à fonctionner pour des dates spécifiques, où la date choisie n'a pas d'importance, mais les dates choisies correspondent en type et en plage à celles réelles.

Ici, sys.argv sera une liste d'au moins une longueur. Créez donc un "fakemain" qui est appelé avec une liste. Ensuite, testez les différentes longueurs de liste probables et leur contenu. Vous pouvez ensuite appeler votre faux main depuis le vrai en passant sys.argv, sachant que fakemain fonctionne, ou modifier la partie "if name..." pour effectuer la fonction normale dans des conditions sans test unitaire.

0voto

flonk Points 584

Vous pouvez attacher un wrapper autour de votre fonction, qui prépare sys.argv avant l'appel et le restaure en quittant :

def run_with_sysargv(func, sys_argv):
""" prépare l'appel avec sys_argv donné et nettoie ensuite. """
    def patched_func(*args, **kwargs):
        old_sys_argv = list(sys.argv)
        sys.argv = list(sys_argv)
        try:
            return func(*args, **kwargs)
        except Exception, err:
            sys.argv = old_sys_argv
            raise err
    return patched_func

Ensuite, vous pouvez simplement faire

def test_parse_args():
    _get_setup_file = run_with_sysargv(get_setup_file, 
                                       ["prog", "-f", "/home/fenton/project/setup.py"])
    setup = _get_setup_file()
    assert setup == "/home/fenton/project/setup.py"

Parce que les erreurs sont correctement transmises, cela ne devrait pas interférer avec les instances externes utilisant le code de test, comme pytest.

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