如何通过传递的命令行参数来测试__name__ ==“ __main __”?

问题描述 投票:0回答:2

[嗨,我想测试我的可执行模块main.py。在此模块中,函数main()具有两个参数:

# main.py

def main(population_size: int, number_of_iterations: int):
    ...

在该模块的底部,有接受命令行参数并执行main功能的逻辑:

# main.py

if __name__ == "__main__":
    # create parser and handle arguments
    PARSER = argparse.ArgumentParser()
    PARSER.add_argument("--populationSize",
                        type=int,
                        default=-1,
                        help="Number of individuals in one iteration")
    PARSER.add_argument("--numberOfIterations",
                        type=int,
                        default=-1,
                        help="Number of iterations in one run")
    # parse the arguments
    ARGS = PARSER.parse_args()

    main(ARGS.populationSize, ARGS.numberOfIterations)

我想测试传递的命令行参数。我的测试方法无效:

# test_main.py

@staticmethod
@mock.patch("argparse.ArgumentParser.parse_args")
@mock.patch("main.main")
def test_passing_arguments(mock_main, mock_argparse):
    """Test passing arguments."""
    mock_argparse.return_value = argparse.Namespace(
         populationSize=4, numberOfIterations=3)
    imp.load_source("__main__", "main.py")

    mock_main.assert_called_with(4, 3)

我得到的错误是没有调用mock_main。我不知道为什么据我了解,我模拟了main模块中的main函数。 main函数的模拟是必要的,因为它很耗时,而我只想在这里测试的是正确地传递了参数。

[从this post开始,我模拟了argparse模块。

python unit-testing mocking argparse
2个回答
3
投票

就像要测试的所有代码一样,将其包装在函数中。

def parse_my_args(argv=None):
    PARSER = argparse.ArgumentParser()
    PARSER.add_argument("--populationSize",
                    type=int,
                    default=-1,
                    help="Number of individuals in one iteration")
    PARSER.add_argument("--numberOfIterations",
                    type=int,
                    default=-1,
                    help="Number of iterations in one run")
    # parse the arguments
    return PARSER.parse_args(argv)


if __name__ == '__main__':
    args = parse_my_args()
    main(args.populationSize, args.numberOfIterations)

ArgumentParser.parse_args处理您传递的任何字符串列表。通过None时,它将改为使用sys.argv[1:]

现在您可以通过传递所需的任何参数列表来简单地测试parse_my_args

# test_main.py

@staticmethod
def test_passing_arguments():
    """Test passing arguments."""
    args = parse_my_args(["--populationSize", "4", "--numberOfIterations", "3"])
    assert args.populationSize == 4
    assert args.numberOfIterations == 3

[如果您进一步想验证是否将正确的参数传递给main,则将that包装在一个函数中,并像上面一样使用模拟程序。

def entry_point(argv=None):
    args = parse_my_args(argv)
    main(args.populationSize, args.numberOfIterations)

if __name__ == '__main__':
    entry_point()

@staticmethod
@mock.patch("main.main")
def test_passing_arguments(mock_main):
    """Test passing arguments."""
    entry_point(["--populationSize", "4", "--numberOfIterations", "3"])
    mock_main.assert_called_with(4, 3)

2
投票

我通常这样写我的命令行代码。首先将现有的main函数重命名为其他名称,例如run()(或其他名称):

def run(population_size: int, number_of_iterations: int):
    ...

然后编写一个main()函数,该函数可实现命令行界面和参数解析。让它接受argv作为可选参数,非常适合测试:

def main(argv=None):
    parser = argparse.ArgumentParser()
    ...
    args = parser.parse_args(argv)
    run(args.popuplation_size, args.number_of_iterations)

然后将其放在模块主体中:

if __name__ == '__main__':
    sys.exit(main())

现在您有了适当的main()函数,您可以轻松测试而无需大惊小怪地调用它的上下文或进行任何奇怪的monkeypatching,例如像:

main(['--populationSize', '4', '--numberOfIterations', '3'])
© www.soinside.com 2019 - 2024. All rights reserved.