如何在目录中运行所有Python单元测试?
我有一个文件夹,里面放着我的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 个回答
你可以使用一个测试运行器来帮你完成这个工作。比如说,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)
在Python 3中,如果你使用的是 unittest.TestCase
,那么你需要注意以下几点:
- 在你的
test
目录下,必须有一个空的(或者其他内容的)__init__.py
文件,这个目录的名字必须是test/
。 - 你在
test/
目录下的测试文件名需要符合test_*.py
的格式。- 这些测试文件可以放在
test/
目录下的子目录里。子目录的名字可以随便起,但每个子目录里也必须有一个__init__.py
文件。
- 这些测试文件可以放在
- 你的测试函数名应该以
test_
开头。例如:test_text_matcher
。
然后,你可以通过以下方式运行所有的测试:
python -m unittest
完成了!这段解决方案不到100行。希望其他Python初学者能通过找到这个节省时间。
在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文档中了解更多信息。