Как я могу использовать mock, чтобы вернуть None для разбора известных аргументов?

#python-3.x #unit-testing #mocking #argparse #python-unittest

#python-3.x #модульное тестирование #издевательство #argparse #python-unittest

Вопрос:

Ниже у меня есть функция, которая возвращает две даты на основе ввода из командной строки. Как я могу использовать mock, чтобы сделать так, чтобы я мог выполнять модульное тестирование в инструкции else?

 # time from of pull
def time_frame():
    """
    checks for optional user input for start and end date of data pull
    creates start and end date for query
    :return: start and end date
    """
    # get the dates
    args, leftovers = get_the_args()

    if args.start_dt is not None and args.end_dt is not None:

        return args.start_dt, args.end_dt

    else:

        # get today
        the_today_start_date, the_today_end_date = get_dates_from_today()

        return the_today_start_date, the_today_end_date
  

Я попытался с помощью mock_get_the_args.return_value = mock.Mock(return_value=None), mock.Mock() сделать так, чтобы вывод args get_the_args() функции возвращал None при выполнении этого раздела моего модульного теста? Что мне нужно, чтобы изменить мой макет.Mock() представляет args переменную для этой работы?

Ниже приведен модульный тест на данный момент:

 # the time frame
@mock.patch('src.toolkit.get_dates_from_today')
@mock.patch('src.toolkit.get_the_args')
def test_time_frame(mock_get_the_args, mock_get_dates_from_today):
    # set some dates
    start_date = '2019-01-01'
    end_date = '2019-01-01'
    # mocking
    mock_get_the_args.return_value = mock.Mock(), mock.Mock()
    mock_get_dates_from_today.return_value = mock.Mock(), mock.Mock()

    start_date, end_date = time_frame() 
    mock_get_the_args.assert_called_once()

    mock_get_the_args.return_value = mock.Mock(return_value=None), mock.Mock()
    start_date, end_date = time_frame() 
    mock_get_dates_from_today.assert_called_once()
  

Ответ №1:

Модульное тестирование с argparse кодом немного сложно, потому что обычно оно ожидает ввода из командной строки. Но само тестирование использует командную строку (возможно, с помощью собственного анализатора argparse).

Я предполагаю, что get_the_args настраивает анализатор и возвращает parser.parse_known_args() .

В целях тестирования удобно предоставить себе возможность предоставления явного argv списка.

например:

 def time_frame(argv=None):
    """
    checks for optional user input for start and end date of data pull
    creates start and end date for query
    :return: start and end date
    """
    # get the dates
    args, leftovers = get_the_args(argv)
    ...
  

где get_the_args используется parse_known_args(argv) .

Если argv равно None, то выполняется синтаксический анализ обычной командной строки. Но вы можете предоставить любой список строк, который генерирует желаемые args и extras . По сути, вы можете имитировать командную строку.

Другой вариант — определить args объект пространства имен, например. args = argparse.Namespace(start_dt=None, end_dt='foobar') . Затем вы можете использовать args.start_dt , как и раньше.

Еще одна вещь, которая упрощает тестирование, — это сделать parser запускаемым только тогда, когда код выполняется как скрипт, а не когда он импортирован. То есть поместите это в `if name ==’main‘: block.