如何将命令行参数从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 函数?