python unittest for argparse
我在创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def get_options(prog_version='1.0', prog_usage='', misc_opts=None): options = [] if misc_opts is None else misc_opts parser = ArgumentParser(usage=prog_usage) if prog_usage else ArgumentParser() parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(prog_version)) parser.add_argument('-c', '--config', dest='config', required=True, help='the path to the configuration file') for option in options: if 'option' in option and 'destination' in option: parser.add_argument(option['option'], dest=option.get('destination', ''), default=option.get('default', ''), help=option.get('description', ''), action=option.get('action', 'store')) return parser.parse_args() |
样本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | my_options = [ { "option":"-s", "destination":"remote_host", "default":"127.0.0.1", "description":"The remote server name or IP address", "action":"store" }, ] # Get Command Line Options options = get_options(misc_opts=my_options) print options.config print options.remote_host |
这将被称为:
1 2 3 | $> python myapp.py -c config.yaml $> config.yaml 127.0.0.1 |
现在,我正试图为这个函数创建一个单元测试,但是我的问题是我不能通过测试代码传递命令行参数。
1 2 3 4 5 6 7 8 9 | # mytest.py import unittest from mymodule import get_options class argParseTestCase(unittest.TestCase): def test_parser(self): options = get_options() # ...pass the command line arguments... self.assertEquals('config.yaml', options.config) # ofcourse this fails because I don't know how I will pass the command line arguments |
我的问题是,我需要将命令行参数传递给
预期正确的调用:
什么是"工作中的"/现在不工作:
在详细模式下运行单元测试的
test_parser (main.argParseTestCase) ... mytest.py 1.0 ERROR
ERROR: test_parser (main.argParseTestCase)
Traceback (most recent call last):
File"tests/unit_tests/mytest.py", line 376, in test_parser options = get_options()
File"/root/test/lib/python2.7/site-packages/mymodule.py", line 61, in get_options return parser.parse_args()
File"/usr/local/lib/python2.7/argparse.py", line 1701, in parse_args args, argv = self.parse_known_args(args, namespace)
File"/usr/local/lib/python2.7/argparse.py", line 1733, in parse_known_args namespace, args = self._parse_known_args(args, namespace)
File"/usr/local/lib/python2.7/argparse.py", line 1939, in _parse_known_args start_index = consume_optional(start_index)
File"/usr/local/lib/python2.7/argparse.py", line 1879, in consume_optional take_action(action, args, option_string)
File"/usr/local/lib/python2.7/argparse.py", line 1807, in take_action action(self, namespace, argument_values, option_string)
File"/usr/local/lib/python2.7/argparse.py", line 1022, in call parser.exit(message=formatter.format_help())
File"/usr/local/lib/python2.7/argparse.py", line 2362, in exit _sys.exit(status)
SystemExit: 0
我更喜欢显式地传递参数,而不是依赖于全局可用的属性,如
1 2 3 | def get_options(args, prog_version='1.0', prog_usage='', misc_opts=None): # ... return parser.parse_args(args) |
然后传递参数
1 2 3 4 5 | def main(args): get_options(args) if __name__ =="__main__": main(sys.argv[1:]) |
这样我就可以替换和测试任何我喜欢的参数列表
1 2 | options = get_options(['-c','config.yaml']) self.assertEquals('config.yaml', options.config) |
您的错误消息堆栈很难读取,因为它是带引号的,而不是代码。但我认为
有一个
有两个特殊问题:
生成输入。
parse_args 使用sys.argv[1:] ,除非其argv 参数不是None 参数。因此,您可以通过修改sys.argv 列表(unittest 已经使用了您的命令行值)或向函数和parse_args 传递argv=None 关键字参数来测试解析器。试图使一个用于unittest 代码的命令行与get_options 一起工作太复杂了。捕获输出,尤其是错误产生的
sys.exit 。一种选择是将ArgumentParser 分为不同的error 和/或exit 方法。另一种方法是将函数调用包装在try 块中。
1 | -c, --catch Catch control-C and display results |
而
企业的价值
这测试了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import unittest import sys #from mymodule import get_options def get_options(argv=None, prog_version='1.0', prog_usage='', misc_opts=None): # argv is optional test list; uses sys.argv[1:] is not provided from argparse import ArgumentParser options = [] if misc_opts is None else misc_opts parser = ArgumentParser(usage=prog_usage) if prog_usage else ArgumentParser() parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(prog_version)) parser.add_argument('-c', '--config', dest='config', help='the path to the configuration file') for option in options: if 'option' in option and 'destination' in option: parser.add_argument(option['option'], dest=option.get('destination', ''), default=option.get('default', ''), help=option.get('description', ''), action=option.get('action', 'store')) args = parser.parse_args(argv) print('args',args) return args class argParseTestCase(unittest.TestCase): def test_config(self): sys.argv[1:]=['-c','config.yaml'] options = get_options() self.assertEquals('config.yaml', options.config) def test_version(self): sys.argv[1:]=['-v'] with self.assertRaises(SystemExit): get_options() # testing version message requires redirecting stdout # similarly for a misc_opts test if __name__=='__main__': unittest.main() |