Как проверить требуемые аргументы argparse во время юнит-тестов? - PullRequest
0 голосов
/ 05 июля 2019

Я делаю тесты TDD для argparser.Как я могу проверить аргументы с параметром обязательный ? Мне нужно проверить все параметры, такие как:

  • слишком много аргументов,
  • аргументы не заданы,
  • указан неверный аргумент.

Я могу поднять SystemExit, но это не совсем то, что мне нужно:

    def test_no_arguments(self):
        with patch.object(sys, 'exit') as mock_method:
            self.parser.parse_arguments()
            self.assertTrue(mock_method.called)

Однако, не вызывая выхода из системы, я имеювсегда такие ошибки: test_error

zbx-check-mount.py

class CommandLine:
    def __init__(self):
        self.args_parser = argparse.ArgumentParser(description="Monitoring mounted filesystems",
                                                   formatter_class=argparse.RawTextHelpFormatter)
        self.parsed_args = None

        self.add_arguments()

    def add_arguments(self):
        """
        Add arguments to parser.
        """
        try:
            self.args_parser._action_groups.pop()  # pylint: disable=protected-access
            required = self.args_parser.add_argument_group('required arguments')
            required.add_argument('--fs_name', required=True, help='Given filesystem')
        except argparse.ArgumentError as err:
            log.error('argparse.ArgumentError: %s', err)
            sys.exit(1)

    def parse_arguments(self, args=None):
        """
        Parse added arguments. Then run private method to return values
        """
        self.parsed_args = self.args_parser.parse_args()

        return self.parsed_args.fs_name,

tests

from pyfakefs.fake_filesystem_unittest import TestCase
import os
import sys

try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO

if sys.version_info[0] == 3:
    from unittest.mock import MagicMock, patch
else:
    from mock import MagicMock, patch


sys.path.extend([os.path.join(os.path.dirname(os.path.abspath(__file__)),'..','..', "bin")])
module_name = __import__('zbx-check-mount')


class TestCommandLine(TestCase):

    def setUp(self):
        """
        Method called to prepare the test fixture. This is called immediately before calling the test method
        """
        self.parser = module_name.CommandLine()

    def test_no_arguments(self):
        opts = self.parser.parse_arguments([])
        assert opts.fs_name

    def tearDown(self):
        """
        Method called immediately after the test method has been called and the result recorded.
        """
        pass

Как избежать этой ситуации и проверить другие варианты?

Ответы [ 2 ]

1 голос
/ 05 июля 2019

В def parse_arguments(self, args=None): вы должны передать args в синтаксический анализатор, как в:

self.args_parser.parse_args(args)

parse_args() анализирует sys.argv[1:], или если задан аргумент None. В противном случае он анализирует предоставленный список.

В полном дистрибутиве python есть файл unittest для argparse (test_argparse.py). Это довольно сложно, определяя подкласс ArgumentParser, который фиксирует ошибки и перенаправляет сообщения об ошибках.

Тестирование argparse сложно, потому что оно смотрит на sys.argv, также используются скрипты unittest. И он обычно пытается выйти на ошибки. Это уже обсуждалось в ряде вопросов SO.

0 голосов
/ 05 июля 2019

Если я правильно интерпретирую ваши симптомы, у вас возникли проблемы в тестовом жгуте, потому что ваша исправленная обезьяной реализация sys.exit фактически возвращает, чего не ожидает библиотека argparse.

Введение side_effect , которое вызывает исключение, которое вы можете затем отловить и проверить в модульном тесте, может быть достаточным, чтобы обойти проблему.

...