我想测试一个脚本,看起来像这样:
my_script.py
import argparse, sys
def my_parser(args=sys.argv[1:]):
parser = argparse.ArgumentParser(description="my parser")
parser.add_argument("--my-arg", dest="my_arg", required=True)
args, _ = parser.parse_known_args(args=args)
return args
args = my_parser()
def do_something():
res = 5+1
return res
def main():
use_args = args
res = do_something()
# whatevere here
当我尝试为函数do_something()
运行单元测试时,我总是得到解析器需要输入参数的错误。我的测试是这样的:
my_test.py
from unittest import TestCase
from my_script import sys, do_something
class MyTest(TestCase):
def test_do_something(self):
test_sys_argv = ["dummy", "--my-arg", "dummy_arg"]
with patch.object(sys, "argv", test_sys_argv):
out = do_something()
self.assertEqual(out, 6)
我做补丁的方式不工作。我理解,通过这种方式,我在函数do_something()
中修补对sys.argv
的任何引用,而当调用测试时,sys.argv
为脚本空。
是否有可能在不重构函数内的变量args
的情况下解决这个问题?我想有args
变量my_script.py作为脚本的全局变量。谢谢你的帮助。
如果您想测试my_parser
,只需在测试中手动传递一个输入。如果您想测试do_something
,则根本不需要sys.argv
,因为fn从不使用args。
这里的问题在于
这一行args = my_parser()
在导入脚本时运行,即在测试之前。*将其移动到main或if __name__ == "__main__"
块中。如果你真的想要,没有什么可以阻止args成为全局变量:
args = None
if __name__ == "__main__":
args = my_parser()
我强烈怀疑你只会计算一次参数——在运行时,在这种情况下,我不太确定为什么你不像往常一样使用argparse
而不使用sys.argv.
你试图修补系统。Argv不起作用,因为它发生在导入之后,而函数已经有了一个空的sys。当它第一次被定义时。(可变的默认参数是在定义函数时绑定的,尽管在这种情况下它甚至不重要,因为在进行测试之前,函数被调用。)您可以考虑这样定义它:
def my_parser(args = None):
args = args or sys.argv[1:]
...
sys以来。Argv现在在函数内部被调用,它将在运行时被评估,如果需要,你可以修补它。除了测试之外,我看不出有任何理由这样做,因为您通常不会修改sys。
*你可以通过在test函数内部导入来解决这个问题…但重点是,目前模块中的"全局变量"是而不是导入安全的。我不太确定这里的执行流程是什么。
注:如果你想测试一个命令行应用程序,你可能想看看其中一个测试框架来模拟不同参数的调用。