7 ответов:
вы должны реорганизовать свой код и переместить синтаксический анализ в функцию:
def parse_args(args): parser = argparse.ArgumentParser(...) parser.add_argument... # ...Create your parser as you like... return parser.parse_args(args)затем в
mainфункция вы должны просто вызвать его с:parser = parse_args(sys.argv[1:])(где первый элемент
sys.argvкоторый представляет имя сценария удаляется, чтобы не отправлять его в качестве дополнительного коммутатора во время работы CLI.)в своих тестах вы можете вызвать функцию parser с любым списком аргументов, которые вы хотите проверить:
def test_parser(self): parser = parse_args(['-l', '-m']) self.assertTrue(parser.long) # ...and so on.таким образом вам никогда не придется выполнять код вашего приложения только для тестирования парсера.
Если вам нужно изменить и / или добавить параметры к вашему синтаксическому анализатору позже в вашем приложении, то создайте метод фабрики:
def create_parser(): parser = argparse.ArgumentParser(...) parser.add_argument... # ...Create your parser as you like... return parserвы можете позже манипулировать им, если хотите, и тест может выглядеть так:
class ParserTest(unittest.TestCase): def setUp(self): self.parser = create_parser() def test_something(self): parsed = self.parser.parse_args(['--something', 'test']) self.assertEqual(parsed.something, 'test')
"argparse часть" немного расплывчато, поэтому этот ответ фокусируется на одной части:
parse_argsметод. Это метод, который взаимодействует с вашей командной строкой и получает все переданные значения. В принципе, вы можете издеваться над тем, чтоparse_argsвозвращает, так что ему не нужно на самом деле получать значения из командной строки.import argparse import mock @mock.patch('argparse.ArgumentParser.parse_args', return_value=argparse.Namespace(kwarg1=value, kwarg2=value)) def test_command(mock_args): passвы должны включить все args вашего метода команды в
Namespaceдаже если они не прошли. Дайте этим аргументам значениеNone. (см. docs) Этот стиль полезен для быстрого выполнения тестирования для случаев, когда для каждого аргумента метода передаются разные значения. Если вы решите издеватьсяNamespaceсам по себе для полного отсутствия доверия argparse в ваших тестах, убедитесь, что он ведет себя аналогично фактическомуNamespaceкласса.
сделать свой
main()функция takeargvв качестве аргумента, а не позволять ему читать отsys.argvкак это будет по умолчанию:# mymodule.py import argparse import sys def main(args): parser = argparse.ArgumentParser() parser.add_argument('-a') process(**vars(parser.parse_args(args))) return 0 def process(a=None): pass if __name__ == "__main__": sys.exit(main(sys.argv[1:]))тогда вы можете проверить нормально.
import mock from mymodule import main @mock.patch('mymodule.process') def test_main(process): main([]) process.assert_call_once_with(a=None) @mock.patch('foo.process') def test_main_a(process): main(['-a', '1']) process.assert_call_once_with(a='1')
- заполните свой список arg с помощью
sys.argv.append()а потом позвонитеparse(), проверьте результат и повторите.- вызов из пакетного / bash файла с вашими флагами и флагом dump args.
- Поместите все ваши аргументы разбора в отдельный файл и в
if __name__ == "__main__":вызовите parse и дамп / оцените результаты, а затем протестируйте это из файла batch/bash.
простой способ тестирования парсера:
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) ...другой способ-изменить
sys.argv, а вызовargs = parser.parse_args()есть много примеров тестирования
argparseнаlib/test/test_argparse.py
Я не хотел изменять исходный сценарий подачи, поэтому я просто высмеял
sys.argvучастие в argparse.from unittest.mock import patch with patch('argparse._sys.argv', ['python', 'serve.py']): ... # your test code hereэто прерывается, если реализация argparse изменяется, но достаточно для быстрого тестового сценария. Чувствительность гораздо важнее специфичности в тестовых сценариях в любом случае.
я обнаружил, что самый простой способ, по крайней мере для меня, был просто проверить sys.argv[0] так что смотрите, если python был запущен как
python -m unittestи не разбирать ничего, если это было так.import sys import argparse parser = argparse.ArgumentParser() parser.add_argument('--outdir', help='Directory to output to', \ default='out') parser.add_argument('--file', help='Input file', \ default='section') parser.add_argument('--word', help='Word to look up') if sys.argv[0] == 'python -m unittest': args = parser.parse_args([]) else: args = parser.parse_args()
Comments