如何使用argparse删除CLI参数,以便unittest接受arg列表

4

我想将自己的参数传递到为单元测试设置的文件中。因此,从命令行调用它应该像这样工作:

python Test.py --c keith.ini SomeTests.test_one

目前我遇到了两个问题。

1)Argparse不允许未知参数

用法:Test.py [-h] [--c CONFILE] Test.py: 错误:无法识别的参数:SomeTests.test_one

2)单元测试不允许未知参数。因此,--c fileName未被unittest接受,并返回:

AttributeError: 'module' object has no attribute 'keith'

因此,我的想法是在调用单元测试运行程序之前收集我的参数并将其删除。

import unittest
import argparse

myArgs = None

def getArgs( allArgs ):
    parser = argparse.ArgumentParser( )
    parser.add_argument('--c', dest='conFile', type=str, default=None, help='Config file')
    args = parser.parse_args()

    if ( args.conFile == None ):
        parser.print_help()

    return args


class SomeTests(unittest.TestCase):
    def test_one(self):
        theTest( 'keith' )

    def test_two(self):
        otherTest( 'keith' )

if __name__ == '__main__':
    myArgs = getArgs( sys.argv )
    print 'Config File: ' + myArgs.conFile
    unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))

有趣的是,我刚刚发现了parse_known_args(),所以我将解析行改为:

args = parser.parse_known_args(['--c']). 

我认为这会解决我的问题并提供给我一些可以传递给unittest的东西。不幸的是,我收到了以下错误信息:

Test.py: error: argument --c: expected one argument. 

这应该可以工作吧?


unittest有自己的sys.argv解析器,可能是一个argparse解析器。我认为它在你的脚本之前运行。我不认为有一种方法可以做到你想要的。 - hpaulj
我已经解决了。Python官方文档是错误的。它显示包括已知参数列表,但只有在不为parse_known_args()函数包括参数列表时才起作用。我将parse和extraArgs都打印出来了,它们各自返回正确的列表。所以午饭后我“应该”能够将其余部分解决。 - Keith
我的评论适用于你将测试文件作为参数调用unitest的情况。你是从脚本中调用unitest,所以你有更多的控制权。 - hpaulj
@hpaulj 好的,我终于弄明白了。我已经在下面提供了完整的答案。希望这能帮助下一个寻找这个答案的人。 - Keith
1个回答

4

好的,需要一些努力才行,但是我解决了。这是完全可能的。argparse文档不正确。函数parse_known_args()不应包含已知参数的列表。此外,argparse删除了重要的arg[0]以返回其他命令看到的有效参数列表。我认为这种删除是一个bug。我已经包含了最终的示例代码。

import unittest
import argparse
import sys

myArgs = None

def getArgs( allArgs ):
    parser = argparse.ArgumentParser( )
    parser.add_argument('--c', dest='conFile', type=str, default=None, help='Configuration file. (Required)')
    args, addArgs = parser.parse_known_args( )

    if ( args.conFile == None ):
        parser.print_help()
        sys.exit(2)

    # argparse strips argv[0] so prepend it
    return args, [ sys.argv[0]] + addArgs

def verify( expected, actual ):
    assert expected == actual, 'Test Failed: '

# Reusable Test
def theTest( exp ):
    print 'myargs: ' + str( myArgs )
    verify( exp, 'keith' )

def otherTest( exp ):
    theTest( exp )

class SomeTests(unittest.TestCase):
    def test_one(self):
        theTest( 'keith' )

    def test_two(self):
        otherTest( 'keith2' )

if __name__ == '__main__':
    myArgs, addArgs = getArgs( sys.argv )
    unittest.main( argv=addArgs, testRunner = unittest.TextTestRunner(verbosity=2))

一旦您将此保存到文件中,您可以像下面的示例一样调用它,然后它就能正常工作。

python Test.py                     # Requires config file
python Test.py --c keith.ini       # Runs all tests
python Test.py --c keith.ini SomeTests          # Runs Class
python Test.py --c keith.ini SomeTests.test_one # Runs test

HTH, Enjoy


它确实有用,谢谢你整理这个。只是小小的挑剔一下,getArgs() 没使用 allArgs(而且 addArgs 命名有点奇怪)。 - Russ Schultz
这个例子只是展示如何归类参数。addArgs是additional arguments的缩写。它们不是我的解决方案需要运行的参数。额外的参数被传递给unittest,因为它们有助于控制要运行哪个测试。请参见上面的例子。抱歉我实际代码中剩下的allArgs。 - Keith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接