python unittest for argparse

醉酒当歌 提交于 2019-12-01 01:01:54

Your error message stack is hard to read because it is in quoted form rather than code. But I think the -v argument is producing a sys.exit. version is like help - it's supposed to display a message and then exit. The -v is used by unittest, but is also read by your parser.

There is an argparse unittest module, test/test_argparse.py. You may need a development Python installation to see that. Some tests are straightforward, others use specialized testing structure. Some of that special code creates arguments in the same way you do with options.

The are two special issues:

  • generating the input. parse_args uses sys.argv[1:] unless its argv parameter is not None. So you can test a parser by either modifying the sys.argv list (unittest has already used your commandline values), or by passing a argv=None keyword argument into your function and on to parse_args. Trying to make a commandline meant for the unittest code to work with get_options is too complicated.

  • trapping the output, especially the sys.exit generated by errors. One option is to subclass ArgumentParser and give it a different error and/or exit method. Another is to wrap the function call in a try block.

unittest takes -c argument, but with a different syntax and meaning

 -c, --catch      Catch control-C and display results

and -v is verbose, not version.

=============

This tests the config argument (in a self contained one file form)

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()

I prefer explicitly passing arguments instead of relying on globally available attributes such as sys.argv (which parser.parse_args() does internally). Thus I usually use argparse by passing the list of arguments myself (to main() and subsequently get_options() and wherever you need them):

def get_options(args, prog_version='1.0', prog_usage='', misc_opts=None):
    # ...
    return parser.parse_args(args)

and then pass in the arguments

def main(args):
    get_options(args)

if __name__ == "__main__":
    main(sys.argv[1:])

that way I can replace and test any list of arguments I like

options = get_options(['-c','config.yaml'])
self.assertEquals('config.yaml', options.config) 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!