我有一个包含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,但它是进步。但是我如何传递和显示结果的主要?或者说,我怎样才能让它工作,从而运行这个文件,并运行这个目录下的所有单元测试?


当前回答

我只是在我的基本测试目录中创建了一个discovery .py文件,并为子目录中的任何内容添加了导入语句。然后discover能够通过在discovery .py上运行它来在这些目录中找到我的所有测试

python -m unittest discover ./test -p '*.py'
# /test/discover.py
import unittest

from test.package1.mod1 import XYZTest
from test.package1.package2.mod2 import ABCTest
...

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

其他回答

因为测试发现似乎是一个完整的主题,所以有一些专门的框架来测试发现:

鼻子 Py。测试

更多阅读请点击:https://wiki.python.org/moin/PythonTestingToolsTaxonomy

这个BASH脚本将从文件系统中的任意位置执行python unittest test目录,无论您在哪个工作目录中:它的工作目录总是位于测试目录的位置。

所有测试,独立的$PWD

unittest Python模块对当前目录敏感,除非你告诉它在哪里(使用discover -s选项)。

当你在。/src或。/example工作目录下,并且你需要一个快速的整体单元测试时,这是很有用的:

#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

python -m unittest discover -s "$readlink"/test -v

选定的测试,独立的$PWD

我将这个实用程序文件命名为runone.py,并像这样使用它:

runone.py <test-python-filename-minus-dot-py-fileextension>
#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

(cd "$dirname"/test; python -m unittest $1)

在生产过程中,不需要test/__init__.py文件来增加包/内存开销。

我使用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)——它被忽略了。

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

我只是在我的基本测试目录中创建了一个discovery .py文件,并为子目录中的任何内容添加了导入语句。然后discover能够通过在discovery .py上运行它来在这些目录中找到我的所有测试

python -m unittest discover ./test -p '*.py'
# /test/discover.py
import unittest

from test.package1.mod1 import XYZTest
from test.package1.package2.mod2 import ABCTest
...

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

根据Stephen Cagle的回答,我添加了对嵌套测试模块的支持。

import fnmatch
import os
import unittest

def all_test_modules(root_dir, pattern):
    test_file_names = all_files_in(root_dir, pattern)
    return [path_to_module(str) for str in test_file_names]

def all_files_in(root_dir, pattern):
    matches = []

    for root, dirnames, filenames in os.walk(root_dir):
        for filename in fnmatch.filter(filenames, pattern):
            matches.append(os.path.join(root, filename))

    return matches

def path_to_module(py_file):
    return strip_leading_dots( \
        replace_slash_by_dot(  \
            strip_extension(py_file)))

def strip_extension(py_file):
    return py_file[0:len(py_file) - len('.py')]

def replace_slash_by_dot(str):
    return str.replace('\\', '.').replace('/', '.')

def strip_leading_dots(str):
    while str.startswith('.'):
       str = str[1:len(str)]
    return str

module_names = all_test_modules('.', '*Tests.py')
suites = [unittest.defaultTestLoader.loadTestsFromName(mname) for mname 
    in module_names]

testSuite = unittest.TestSuite(suites)
runner = unittest.TextTestRunner(verbosity=1)
runner.run(testSuite)

的所有子目录。*Tests.py文件,然后加载。它期望每个*Tests.py包含一个单独的类*Tests(unittest.TestCase),这个类会依次加载并执行。

这适用于目录/模块的任意深度嵌套,但在两者之间的每个目录至少需要包含一个空__init__.py文件。这允许测试通过用点替换斜杠(或反斜杠)来加载嵌套模块(参见replace_slash_by_dot)。