如何在目录中运行所有Python单元测试?

480 投票
18 回答
416295 浏览
提问于 2025-04-15 15:59

我有一个文件夹,里面放着我的Python单元测试。每个单元测试文件的名字都是以test_*.py开头的。我想创建一个文件,叫all_test.py,这个文件的作用就是运行所有这些测试文件,并返回结果。到目前为止,我尝试了两种方法,但都失败了。我会把这两种方法分享出来,希望有谁能告诉我正确的做法。

在我第一次勇敢的尝试中,我想:“如果我在这个文件里导入所有的测试模块,然后调用这个unittest.main(),应该就能成功了吧?”结果,我错了。

import glob
import unittest

testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]

if __name__ == "__main__":
     unittest.main()

这并没有成功,我得到的结果是:

$ python all_test.py 

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

在我的第二次尝试中,我想,好的,也许我可以用一种更“手动”的方式来做这个测试。所以我尝试了下面的做法:

import glob
import unittest

testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
[__import__(str) for str in module_strings]
suites = [unittest.TestLoader().loadTestsFromName(str) for str in module_strings]
[testSuite.addTest(suite) for suite in suites]
print testSuite 

result = unittest.TestResult()
testSuite.run(result)
print result

#Ok, at this point I have a result
#How do I display it as the normal unit test command line output?
if __name__ == "__main__":
    unittest.main()

这同样没有成功,但看起来离成功很近了!

$ python all_test.py 
<unittest.TestSuite tests=[<unittest.TestSuite tests=[<unittest.TestSuite tests=[<test_main.TestMain testMethod=test_respondes_to_get>]>]>]>
<unittest.TestResult run=1 errors=0 failures=0>

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

我似乎有一个测试套件,并且可以执行结果。我有点担心的是,它显示我只有run=1,感觉应该是run=2,不过这也是进步。但我该如何把结果传递并显示给主程序呢?或者说,我该怎么做才能让这个文件运行时,自动执行这个文件夹里的所有单元测试呢?

18 个回答

111

你可以使用一个测试运行器来帮你完成这个工作。比如说,nose 就非常好用。当你运行它的时候,它会在当前的文件夹里找到测试并执行这些测试。

更新:

这里有一些我在使用nose之前写的代码。你可能不需要那些模块名称的明确列表,但其他部分可能对你有帮助。

testmodules = [
    'cogapp.test_makefiles',
    'cogapp.test_whiteutils',
    'cogapp.test_cogapp',
    ]

suite = unittest.TestSuite()

for t in testmodules:
    try:
        # If the module defines a suite() function, call it to get the suite.
        mod = __import__(t, globals(), locals(), ['suite'])
        suitefn = getattr(mod, 'suite')
        suite.addTest(suitefn())
    except (ImportError, AttributeError):
        # else, just load all the test cases from the module.
        suite.addTest(unittest.defaultTestLoader.loadTestsFromName(t))

unittest.TextTestRunner().run(suite)
279

在Python 3中,如果你使用的是 unittest.TestCase,那么你需要注意以下几点:

  • 在你的 test 目录下,必须有一个空的(或者其他内容的) __init__.py 文件,这个目录的名字必须是 test/
  • 你在 test/ 目录下的测试文件名需要符合 test_*.py 的格式。
    • 这些测试文件可以放在 test/ 目录下的子目录里。子目录的名字可以随便起,但每个子目录里也必须有一个 __init__.py 文件。
  • 你的测试函数名应该以 test_ 开头。例如: test_text_matcher

然后,你可以通过以下方式运行所有的测试:

python -m unittest

完成了!这段解决方案不到100行。希望其他Python初学者能通过找到这个节省时间。

722

在Python 2.7及更高版本中,你不需要写新的代码或者使用第三方工具来实现这个功能;通过命令行进行递归测试执行是内置的。只需在你的测试目录中放一个__init__.py文件,然后:

python -m unittest discover <test_directory>
# or
python -m unittest discover -s <directory> -p '*_test.py'

你可以在python 2.7或者python 3.x的unittest文档中了解更多信息。

撰写回答