226 votes

Comment écrire des tests pour la partie argparse d'un module python ?

J'ai un module Python qui utilise la bibliothèque argparse. Comment puis-je écrire des tests pour cette section du code de base ?

9voto

Andy Hayden Points 38010

parse_args lance un SystemExit et s'imprime sur stderr, vous pouvez attraper ces deux cas :

import contextlib
import io
import sys

@contextlib.contextmanager
def captured_output():
    new_out, new_err = io.StringIO(), io.StringIO()
    old_out, old_err = sys.stdout, sys.stderr
    try:
        sys.stdout, sys.stderr = new_out, new_err
        yield sys.stdout, sys.stderr
    finally:
        sys.stdout, sys.stderr = old_out, old_err

def validate_args(args):
    with captured_output() as (out, err):
        try:
            parser.parse_args(args)
            return True
        except SystemExit as e:
            return False

Vous inspectez stderr (en utilisant err.seek(0); err.read() mais cette granularité n'est généralement pas nécessaire.

Vous pouvez maintenant utiliser assertTrue ou tout autre test que vous souhaitez :

assertTrue(validate_args(["-l", "-m"]))

Alternativement, vous pourriez vouloir attraper et relancer une erreur différente (au lieu de SystemExit ) :

def validate_args(args):
    with captured_output() as (out, err):
        try:
            return parser.parse_args(args)
        except SystemExit as e:
            err.seek(0)
            raise argparse.ArgumentError(err.read())

7voto

hpaulj Points 6132

Une façon simple de tester un analyseur syntaxique est :

parser = ...
parser.add_argument('-a',type=int)
...
argv = '-a 1 foo'.split()  # or ['-a','1','foo']
args = parser.parse_args(argv)
assert(args.a == 1)
...

Une autre façon est de modifier sys.argv et appeler args = parser.parse_args()

Il existe de nombreux exemples de tests argparse en lib/test/test_argparse.py

4voto

guest Points 41

Lorsque vous transmettez les résultats de argparse.ArgumentParser.parse_args à une fonction, j'utilise parfois un namedtuple pour simuler des arguments à tester.

import unittest
from collections import namedtuple
from my_module import main

class TestMyModule(TestCase):

    args_tuple = namedtuple('args', 'arg1 arg2 arg3 arg4')

    def test_arg1(self):
        args = TestMyModule.args_tuple("age > 85", None, None, None)
        res = main(args)
        assert res == ["55289-0524", "00591-3496"], 'arg1 failed'

    def test_arg2(self):
        args = TestMyModule.args_tuple(None, [42, 69], None, None)
        res = main(args)
        assert res == [], 'arg2 failed'

if __name__ == '__main__':
    unittest.main()

2voto

vczm Points 494

Pour tester le CLI (interface de ligne de commande), et pas de sortie de commande J'ai fait quelque chose comme ça

import pytest
from argparse import ArgumentParser, _StoreAction

ap = ArgumentParser(prog="cli")
ap.add_argument("cmd", choices=("spam", "ham"))
ap.add_argument("-a", "--arg", type=str, nargs="?", default=None, const=None)
...

def test_parser():
    assert isinstance(ap, ArgumentParser)
    assert isinstance(ap, list)
    args = {_.dest: _ for _ in ap._actions if isinstance(_, _StoreAction)}

    assert args.keys() == {"cmd", "arg"}
    assert args["cmd"] == ("spam", "ham")
    assert args["arg"].type == str
    assert args["arg"].nargs == "?"
    ...

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