我有一个包含Python单元测试的目录。每个单元测试模块的格式是test_*.py。我正在尝试创建一个名为all_test.py的文件,您猜对了,它将以上述测试形式运行所有文件并返回结果。到目前为止,我尝试了两种方法;两者都失败了。我将展示这两种方法,我希望有人知道如何正确地做到这一点。

对于我的第一次勇敢的尝试,我想“如果我只是导入文件中的所有测试模块,然后调用这个unittest.main() doodad,它就会工作,对吗?”事实证明我错了。

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

我似乎有一个某种类型的套件,我可以执行结果。我有点担心这个事实,它说我只运行=1,似乎应该运行=2,但它是进步。但是我如何传递和显示结果的主要?或者说,我怎样才能让它工作,从而运行这个文件,并运行这个目录下的所有单元测试?


当前回答

我尝试了各种方法,但都有缺陷,或者我必须编写一些代码,这很烦人。但是在linux下有一种方便的方法,那就是通过特定的模式找到每个测试,然后逐个调用它们。

find . -name 'Test*py' -exec python '{}' \;

最重要的是,它确实有效。

其他回答

你可以用一个测试者来帮你做这件事。鼻子就是个很好的例子。运行时,它将在当前树中找到测试并运行它们。

更新:

这是我在没有鼻子之前写的一些代码。您可能不想要显式的模块名称列表,但其余的可能对您有用。

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)

在python3中,如果你使用unittest。TestCase:

你的测试目录中必须有一个空的(或其他)__init__.py文件(必须命名为test/) 您的测试文件在test/ match模式test_*.py。 它们可以在test/下的子目录中。这些子dirs可以被命名为任何东西,但它们都需要有一个__init__.py文件

然后,您可以使用以下工具运行所有测试:

python -m unittest

完成了!一个少于100行的解决方案。希望其他python初学者可以通过找到这个来节省时间。

这是一个老问题,但现在(2019年)对我有用的是:

python -m unittest *_test.py

我的所有测试文件都在与源文件相同的文件夹中,它们以_test结尾。

我使用PyDev/LiClipse,还没有真正弄清楚如何从GUI一次运行所有测试。(编辑:右键单击根测试文件夹并选择运行为-> Python unit-test

这是我目前的解决方案:

import unittest

def load_tests(loader, tests, pattern):
    return loader.discover('.')

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

我把这些代码放在一个名为all in我的测试目录的模块中。如果我从LiClipse运行这个模块作为单元测试,那么所有测试都将运行。如果我要求只重复特定或失败的测试,则只运行这些测试。它也不会干扰我的命令行测试运行器(nosetests)——它被忽略了。

您可能需要根据项目设置更改要发现的参数。

通过研究上面的代码(特别是使用TextTestRunner和defaultTestLoader),我能够非常接近。最终,我通过将所有测试套件传递给单个套件构造函数来修复代码,而不是“手动”添加它们,这解决了我的其他问题。这就是我的解。

import glob
import unittest

test_files = glob.glob('test_*.py')
module_strings = [test_file[0:len(test_file)-3] for test_file in test_files]
suites = [unittest.defaultTestLoader.loadTestsFromName(test_file) for test_file in module_strings]
test_suite = unittest.TestSuite(suites)
test_runner = unittest.TextTestRunner().run(test_suite)

是的,用鼻子可能比用这个简单,但这不是重点。