如何将命令行参数从pytest传递给代码

Posted

技术标签:

【中文标题】如何将命令行参数从pytest传递给代码【英文标题】:how to pass command line argument from pytest to code 【发布时间】:2019-06-01 22:28:19 【问题描述】:

我正在尝试将参数从 pytest 测试用例传递给正在测试的模块。例如,使用来自Python boilerplate 的 main.py,我可以从命令行运行它:

$ python3 main.py
usage: main.py [-h] [-f] [-n NAME] [-v] [--version] arg
main.py: error: the following arguments are required: arg
$ python3 main.py xx
hello world
Namespace(arg='xx', flag=False, name=None, verbose=0)

现在我正在尝试对 pytest 做同样的事情,使用以下 test_sample.py

(注意: main.py 需要命令行参数。但是这些参数需要在特定的测试中硬编码,它们不应该是 pytest 的命令行参数。pytest 测试用例只需要将这些值作为命令行参数发送到 main.main()。)

import main
def test_case01():
    main.main()
    # I dont know how to pass 'xx' to main.py,
    # so for now I just have one test with no arguments

并以如下方式运行测试:

pytest -vs test_sample.py

这会失败并显示错误消息。我试图查看其他答案以获得解决方案,但无法使用它们。例如,42778124 建议创建一个单独的文件 run.py,这是不可取的。而48359957 和40880259 似乎更多地处理 pytest 的命令行参数,而不是将命令行参数传递给主代码。

我不需要 pytest 来获取命令行参数,参数可以在特定测试中硬编码。但是这些参数需要作为参数传递给主代码。你能给我一个 test_sample.py,它用一些参数调用 main.main() 吗?

【问题讨论】:

你可以使用猴子补丁。 def test_case01(monkeypatch): with monkeypatch.context() as m: m.setattr(sys, 'argv', ['my', 'dummy', 'args']); main()。在上下文块中,sys.argv 列表使用您的值进行了猴子补丁。 你在测试哪个 - 命令行界面,或者它背后的代码 - 使用解析的args的函数和类? @hpaulj:我正在测试使用已解析参数的函数。 @hoefling:我已经接受了另一个答案,它对我来说只需最少的代码更改。但是我没看懂你的评论,能否给你补充一个详细的答案,以便我以后可以使用你的解决方案? 【参考方案1】:

如果您无法修改main 方法的签名,您可以使用monkeypatching 技术将参数临时替换为测试数据。示例:想象为以下程序编写测试:

import argparse


def main():
    parser = argparse.ArgumentParser(description='Greeter')
    parser.add_argument('name')
    args = parser.parse_args()
    return f'hello args.name'


if __name__ == '__main__':
    print(main())

从命令行运行时:

$ python greeter.py world
hello world

要使用一些自定义数据测试 main 函数,monkeypatch sys.argv

import sys
import greeter

def test_greeter(monkeypatch):
    with monkeypatch.context() as m:
        m.setattr(sys, 'argv', ['greeter', 'spam'])
        assert greeter.main() == 'hello spam'

与parametrizing 技术结合使用时,无需修改测试函数即可轻松测试不同的参数:

import sys
import pytest
import greeter

@pytest.mark.parametrize('name', ['spam', 'eggs', 'bacon'])
def test_greeter(monkeypatch, name):
    with monkeypatch.context() as m:
        m.setattr(sys, 'argv', ['greeter', name])
        assert greeter.main() == 'hello ' + name

现在你得到三个测试,每个参数一个:

$ pytest -v test_greeter.py

...

test_greeter.py::test_greeter[spam] PASSED
test_greeter.py::test_greeter[eggs] PASSED
test_greeter.py::test_greeter[bacon] PASSED

【讨论】:

【参考方案2】:

最好使用这种代码,而不是从 main 方法中读取参数。

# main.py
def main(arg1):
    return arg1

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='My awesome script')
    parser.add_argument('word', help='a word')
    args = parser.parse_args()
    main(args.word)

这样,你的 main 方法可以很容易地在 pytest 中测试

import main
def test_case01():
    main.main(your_hardcoded_arg)

我不确定您是否可以调用 python 脚本进行测试,除非使用 os 模块,这可能不是一个好习惯

【讨论】:

对于其他人无需进入猴子补丁即可查看此问题,here 也是一个不错的解决方案。顺便说一句,为什么这个被接受的答案被否决了?

以上是关于如何将命令行参数从pytest传递给代码的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数从 bat 文件或命令行传递给 plpgsql 函数?

pytest文档10-命令行传参

如何将任意命令行参数从 MinGW shell 传递给本机 Windows 程序?

将命令行参数和文本文件传递给程序

将命令行参数输入文件传递给要解析的类

将命令行参数从 VB 传递到 C# WPF 应用程序