【问题标题】:Python - unittest trying to call imported custom argparserPython - unittest 尝试调用导入自定义 argparse
【发布时间】:2014-02-01 16:01:41
【问题描述】:

我有一个单元测试,它想根据单元测试的命令行选项调用导入的模块来执行parse_os,但似乎单元测试无法识别该选项,任何想法:

./python testParser.py --mac
option --mac not recognized
Usage: testParser.py [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -q, --quiet      Minimal output
  -f, --failfast   Stop on first failure
  -c, --catch      Catch control-C and display results
  -b, --buffer     Buffer stdout and stderr during test runs

Examples:
 testParser.py                               - run default set of tests
 testParser.py MyTestSuite                   - run suite 'MyTestSuite'
 testParser.py MyTestCase.testSomething      - run MyTestCase.testSomething
 testParser.py MyTestCase                    - run all 'test*' test methods
                                           in MyTestCase

我想像这样运行我的单元测试程序:python testParser.py --mac

已编辑:现在可以通过将 'unittest.main()' 更改为:

runner = unittest.TextTestRunner(stream=stderr_file)
itersuite = unittest.TestLoader().loadTestsFromTestCase(TT28046_ForensicSearchSmokeTest)
runner.run(itersuite)

单元测试程序:

import logging
import unittest

from myargparse import *

class MyTest(unittest.TestCase):

   def test_parse_os(self):
        ## Parse the args:
       self.install = install_sw(parse_os(arg=""))
       print 'Which os? %s' % self.install

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    # get the default logger
    logger = logging.getLogger()
    # add a file handler
    logger.addHandler(logging.FileHandler('stdout.txt', mode='w'))
    # set up a stream for all stderr output
    stderr_file = open('stderr.txt', 'w')
    # attach that stream to the testRunner
    unittest.main(testRunner=unittest.TextTestRunner(stream=stderr_file))

我导入的模块:

import argparse
import os
import sys

def parse_os(arg):
    my_os = ''
    parser = argparse.ArgumentParser()
    parser.add_argument("-m", "--mac",
                    action="store_true")
    parser.add_argument("-w", "--win",
                    action="store_true")
    args = parser.parse_args()

    if args.mac:
       print 'Mac'
       my_os = "Mac"
    if args.win:
       print 'Windows'
       my_os = "Windows"
    return my_os

def install_sw(my_os):
    installed_os = None
    if my_os == 'Mac':
        print 'Installing Mac...'
        installed_os = 'Mac'
    if my_os == 'Windows':
        print 'Installing Windows...'
        installed_os = 'Windows'
    return installed_os

【问题讨论】:

  • 你不能也不应该sys.argv 是一个简单的列表,因此您可以更改/替换它的内容。

标签: python argparse python-unittest


【解决方案1】:

sys.argv 变量是一个简单的list,因此您可以随意修改/替换它。 在这种情况下,我会考虑使用上下文管理器,如下所示:

class SysArgv(object):
    def __init__(self, argv):
        self._old_argv = sys.argv
        sys.argv = argv
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_value, tb):
        sys.argv = self._old_argv
        return False

并用作:

In [4]: with SysArgv(['a', 'b', 'c']):
   ...:     print(sys.argv)
   ...:     
['a', 'b', 'c']

在你的情况下,简单地包装测试代码,如:

with SysArgv(['the_module_name.py', '--mac']):
    # test code goes here

argparse 模块会看到你想要的参数。

至于在运行测试时将参数传递给 unittest 模块,可以将 argv 参数传递给 unittest.main。来自文档:

The `argv` argument can be a list of options passed to the program, with the first element being the program name. If not specified or `None`, the values of `sys.argv` are used.

但是在这种情况下,您应该在调用 unittest.main 之前修改 sys.argv 变量:

if __name__ == '__main__':
    options = ['name_of_module.py'] + sys.argv[-1:]   # last argument as option for the test
    with SysArgv(sys.argv[:-1]):   # or modify how you want
        unittest.main(argv=options)

【讨论】:

  • 这是否也适用于 --keyword value 参数?
【解决方案2】:

您是否尝试过仅使用“-m”而不是“--mac”?

你也可以试试:

import optparse

parser = optparse.OptionParser()
parser.add_option("-m", "--mac",
              dest="mac",
              action="store_true",
              help="Run as Mac")
parser.add_option("-w", "--win",
              dest="win",
              action="store_true",
              help="Run as Win")

(options, args) = parser.parse_args()

【讨论】:

  • 您误解了这个问题。问题是不是解析器。是不是他正在调用unittest.main,它查看sys.argv 并引发异常,因为它无法识别该选项。在测试运行之前就引发了异常。
【解决方案3】:

感谢大家的建议,但我决定这样做是为了限制对我的程序的更改。

我没有调用“unittest.main()”,而是改为调用以下代码:

runner = unittest.TextTestRunner(stream=stderr_file)
itersuite = unittest.TestLoader().loadTestsFromTestCase(MyTest)
runner.run(itersuite)

【讨论】:

    【解决方案4】:

    根据这里的所有答案,我最初做了这个简单的 hack,并且成功了:

    # Change sys.argv before unittest tries to parse our args
    sys.argv = [sys.argv[0]]  # Replace with only the first arg
    unittest.main()
    

    我意识到我仍然可以使用所有最统一的命令行参数,在我的情况下,我只是传递了一堆路径,所以任何以“-”开头的东西都可以传递,没有必要破解自unittest.main() 以来的任何内容都有argv 参数

    # Pass on options, and more importantly, don't pass on ALL args
    options = [sys.argv[0]] + [a for a in sys.argv if a.startswith("-")]
    unittest.main(argv=options)
    

    【讨论】:

      【解决方案5】:

      只需过滤掉所有 argparse 而不是 arparse 参数,然后将那些不是 argparse 参数的参数发送到 sys.argv 这是 unittest 使用的一个:

      args, notknownargs = parser.parse_known_args()
      sys.argv[1:] = notknownargs
      

      【讨论】:

        猜你喜欢
        • 2013-08-21
        • 2013-12-14
        • 1970-01-01
        • 2016-12-25
        • 2018-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多