argparse的python单元测试

argparse的python单元测试,python,python-2.7,unit-testing,argparse,Python,Python 2.7,Unit Testing,Argparse,我在模块中有一个函数,用于创建argparse: 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_argu

我在模块中有一个函数,用于创建
argparse

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()
示例
myapp.py
为:

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
这将被称为:

$> python myapp.py -c config.yaml
$> config.yaml
   127.0.0.1
现在,我正试图为这个函数创建一个单元测试,但我的问题是我不能通过测试代码传递命令行参数

# 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
我的问题是我需要将命令行参数传递给
get_options()
,但我不知道如何正确执行

预期正确的调用:
python mytest.py
-c config.yaml
应该以某种方式在测试代码内部传递。)

什么是“工作”/“现在不工作”:

  • python mytest.py-c config.yaml
    也不起作用。返回
    AttributeError:“module”对象没有属性“config”
    ,因为它希望我调用
    argParseTestCase
    。换句话说,
    python mytest.py-c argParseTestCase
    “起作用”,但当然是一个返回
    AssertionError:'config.yaml'!='argParseTestCase'
  • python mytest.py-v
    在详细模式下运行单元测试也会失败。它返回:

    测试解析器(main.argParseTestCase)。。。mytest.py 1.0错误 错误:测试语法分析器(main.argParseTestCase)
    回溯(最近一次呼叫最后一次): 文件“tests/unit\u tests/mytest.py”,第376行,在test\u parser options=get\u options()中 文件“/root/test/lib/python2.7/site packages/mymodule.py”,第61行,在get\u options return parser.parse\u args()中 文件“/usr/local/lib/python2.7/argparse.py”,第1701行,在parse_args args中,argv=self.parse_known_args(args,名称空间)
    文件“/usr/local/lib/python2.7/argparse.py”,第1733行,在parse_known_args名称空间中,args=self.\u parse_known_args(args,名称空间)
    文件“/usr/local/lib/python2.7/argparse.py”,第1939行,在_parse_known_args start_index=consume_optional(start_index)
    文件“/usr/local/lib/python2.7/argparse.py”,第1879行,在consume\u optional take\u action(action,args,option\u string)中
    文件“/usr/local/lib/python2.7/argparse.py”,第1807行,在take\u action(self、名称空间、参数值、选项字符串)中
    文件“/usr/local/lib/python2.7/argparse.py”,第1022行,在callparser.exit(message=formatter.format\u help())中
    文件“/usr/local/lib/python2.7/argparse.py”,第2362行,在exit_sys.exit(状态)中 系统出口:0


  • 您的错误消息堆栈很难读取,因为它是引用的形式,而不是代码。但是我认为
    -v
    参数正在生成一个
    sys.exit
    <代码>版本类似于
    帮助
    ——它应该显示一条消息,然后退出。
    -v
    unittest
    使用,但也由解析器读取

    有一个
    argparse
    unittest模块,
    test/test\u argparse.py
    。您可能需要安装一个开发Python才能看到这一点。有些测试是直接的,有些则使用专门的测试结构。某些特殊代码创建参数的方式与使用
    选项的方式相同

    这是两个特别问题:

    • 生成输入
      parse_args
      使用
      sys.argv[1://code>,除非其
      argv
      参数不是
      None
      。因此,您可以通过修改
      sys.argv
      列表(
      unittest
      已经使用了您的命令行值),或者通过将
      argv=None
      关键字参数传递到函数并转到
      parse_args
      来测试解析器。试图为
      unittest
      代码创建一条命令行以与
      get\u选项
      一起工作太复杂了

    • 捕获输出,尤其是错误生成的
      sys.exit
      。一个选项是子类化
      ArgumentParser
      ,并给它一个不同的
      error
      和/或
      exit
      方法。另一种方法是将函数调用包装在
      try
      块中

    unittest
    接受
    -c
    参数,但语法和含义不同

     -c, --catch      Catch control-C and display results
    
    -v
    详细的
    ,而不是
    版本

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

    这将测试
    config
    参数(以自包含的单文件形式)


    我更喜欢显式地传递参数,而不是依赖全局可用的属性,例如
    sys.argv
    (parser.parse_args()
    在内部执行)。因此,我通常使用
    argparse
    来传递参数列表(到
    main()

    然后传入参数

    def main(args):
        get_options(args)
    
    if __name__ == "__main__":
        main(sys.argv[1:])
    
    这样我就可以替换和测试我喜欢的任何参数列表

    options = get_options(['-c','config.yaml'])
    self.assertEquals('config.yaml', options.config) 
    
    def main(args):
        get_options(args)
    
    if __name__ == "__main__":
        main(sys.argv[1:])
    
    options = get_options(['-c','config.yaml'])
    self.assertEquals('config.yaml', options.config)