Как вы пишете тесты для части argparse модуля python?



У меня есть модуль Python, который использует библиотека argparse. Как написать тесты для этого раздела базы кода?

717   7  

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() функция take argv в качестве аргумента, а не позволять ему читать от 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')
  1. заполните свой список arg с помощью sys.argv.append() а потом позвоните parse(), проверьте результат и повторите.
  2. вызов из пакетного / bash файла с вашими флагами и флагом dump args.
  3. Поместите все ваши аргументы разбора в отдельный файл и в 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

    Ничего не найдено.