如何使用 mock to return None 来解析已知参数?

How can I use mock to return None for parse known args?

下面我有一个函数 returns 基于命令行输入的两个日期。我如何使用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() 使 get_the_args() 函数的 args 输出 returns None 当我的单元测试的这一部分运行时?我需要更改代表 args 变量的 mock.Mock() 什么才能使它起作用?

以下是到目前为止的单元测试:

# 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()

使用 argparse 代码进行单元测试有点棘手,因为它通常需要来自命令行的输入。但是测试本身使用命令行(可能使用它自己的 argparse 解析器)。

我假设 get_the_args 设置了一个解析器,并且 returns 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,那么它会解析常规命令行。但是您可以提供生成所需 argsextras 的任何字符串列表。实际上,您可以模拟命令行。

另一种选择是定义一个 args 命名空间对象,例如。 args = argparse.Namespace(start_dt=None, end_dt='foobar')。然后你可以像以前一样使用args.start_dt

使测试更容易的另一件事是仅当代码 运行 作为脚本时才使 parser 为 运行,而不是在导入时。即放在`if name =='main': block.