将Python脚本参数传递给测试模块

6 投票
3 回答
1741 浏览
提问于 2025-04-17 08:19

我有几个测试模块,这些模块都是通过一个驱动脚本一起调用的,这个脚本可以接受各种参数。测试本身是用Python的unittest模块写的。

import optparse
import unittest
import sys
import os

from tests import testvalidator
from tests import testmodifier
from tests import testimporter

#modify the path so that the test modules under /tests have access to the project root
sys.path.insert(0, os.path.dirname(__file__))

def run(verbosity):
    if verbosity == "0":
            sys.stdout = open(os.devnull, 'w')

    test_suite = unittest.TestSuite()
    test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(testvalidator.TestValidator))
    test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(testmodifier.TestModifier))
    test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(testimporter.TestDataImporter))

    unittest.TextTestRunner(verbosity=int(verbosity)).run(test_suite)

if __name__ == "__main__":

    #a simple way to control output verbosity
    parser = optparse.OptionParser()
    parser.add_option("--verbosity", "--verbosity", dest="verbosity", default="0")
    (options, args) = parser.parse_args()

    run(options.verbosity)

我的问题是,在这些测试模块中,有些测试我想根据传给驱动的不同参数来跳过。我知道unittest提供了一些装饰器可以做到这一点,但我不太清楚怎么把这些信息传递给各个模块。例如,如果我有一个--skip-slow的参数,我该怎么标记那些慢的测试,让它们被跳过呢?

谢谢你的时间。

3 个回答

0

这是我解决这个问题的方法。在我的模块底部,我放了这段代码,用来根据命令行参数中是否有 --slow 来设置一个全局变量:

if __name__ == "__main__":
    try:
        i = sys.argv.index("--slow")
        run_slow_tests=True
        del sys.argv[i]
    except ValueError:
        pass

    unittest.main()

然后在那些运行会比较慢的测试函数开头,我加了这条语句。如果没有设置包含慢测试的标志,它会抛出一个 unittest.SkipTest() 异常

if not run_slow_tests:
    raise unittest.SkipTest('Slow test skipped, unless --slow given in sys.argv.')

这样,当我正常调用这个模块时,慢测试就会被跳过。

% python src/my_test.py -v       
test_slow (__main__.Tests) ... skipped 'Slow test skipped, unless --slow given in sys.argv.'

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK (skipped=1)

而当我加上 --slow 参数时,这个模块里的慢测试就会运行:

% python src/my_test.py -v --slow
test_slow (__main__.Tests) ... ok

----------------------------------------------------------------------
Ran 1 test in 10.110s

OK

不过,不幸的是,这个方法在 Unittest的测试发现中并不奏效。

% python -m unittest discover src "*_test.py" --slow
usage: python -m unittest discover [-h] [-v] [-q] [--locals] [-f] [-c] [-b]
                                   [-k TESTNAMEPATTERNS] [-s START]
                                   [-p PATTERN] [-t TOP]
python -m unittest discover: error: unrecognized arguments: --slow

而且使用 @unittest.SkipUnless() 装饰器也不行。我猜这是因为这个装饰器在模块定义时就评估它的参数,而这个参数在模块运行时才会被设置为正确的值,时间上是晚了一点。

虽然这个方法不是完美的,但它让我可以在Python的标准库中工作。像这样的需求是一个很好的理由去采用更好的框架,比如 nose tests。不过对于我当前的项目,我更倾向于不安装任何外部模块。

2

你可以使用 nose 测试工具,配合 attrib 插件,这样你就可以根据测试用例的属性来选择测试案例。特别是,插件文档中的例子使用了 @attr(slow) 来标记那些运行比较慢的测试用例。

之后,在命令行中,你可以这样操作:

  • 如果你想选择所有标记为 slow 的测试用例,可以输入:

    $ nosetests -a slow

  • 如果你想选择所有没有标记为 slow 的测试用例,可以输入:

    $ nosetests -a '!slow'

2

其实我之前也在想这个问题,最后终于找到了答案。

主文件...

...
if __name__ == '__main__':
    args = argparser()

    from tests import *

    ...

然后在你的测试模块里,只需要这样做:

from __main__ import args

print args

我试了一下,效果很好。最棒的是,这个方法非常简单,根本不算什么黑科技。

撰写回答