J'ai un module Python qui utilise la bibliothèque argparse. Comment puis-je écrire des tests pour cette section du code de base ?
Réponses
Trop de publicités?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())
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
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()
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 == "?"
...
- Réponses précédentes
- Plus de réponses