我有一个目录,包含我的蟒蛇单元的测试。每个单元的测试模块的形式 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, 但这是取得进展。但我怎么通过和显示的结果主要?或者我怎么基本上获得它的工作这样我就可以运行这个文件,并在这样做时,运行的所有单元的测试这个目录?

有帮助吗?

解决方案

您可以使用一个测试运行器会为你做这个。 鼻子是例如非常好。在运行时,它会发现在当前树测试和运行它们。

更新:

下面是从我的前鼻天一些代码。你可能不希望模块名称的显式列表,但也许剩下的将是对你有用。

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 2.7和更高不必编写新代码或者使用第三方工具来做到这一点;通过命令行递归测试执行内置。

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

可以读取更多的在蟒2.7 蟒3.x的单元测试的文档

这是现在可以直接从单元测试: unittest.TestLoader。发现

import unittest
loader = unittest.TestLoader()
start_dir = 'path/to/your/test/files'
suite = loader.discover(start_dir)

runner = unittest.TextTestRunner()
runner.run(suite)

在 python 3 中,如果您使用 unittest.TestCase:

  • 您必须有一个空的(或其他) __init__.py 文件在你的 test 目录 (必须 被命名 test/)
  • 你的测试文件在里面 test/ 匹配模式 test_*.py. 。它们可以位于以下子目录中 test/, ,并且这些子目录可以命名为任何名称。

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

python -m unittest

完毕!少于 100 行的解决方案。希望另一个Python初学者能找到这个来节省时间。

通过井(特别是使用TextTestRunnerdefaultTestLoader)研究比特以上代码中,我是能够得到相当接近。最后,我也通过刚才的所有测试套件传递到单人套房的构造,而不是“人工”添加它们,固定我的其他问题固定我的代码。因此,这里是我的解决方案。

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)

是的,这可能更容易只是用鼻子不是要做到这一点,但是这是除了点。

如果你想运行各种测试用例类所有的测试,你很高兴他们指定明确的,那么你可以做这样的:

from unittest import TestLoader, TextTestRunner, TestSuite
from uclid.test.test_symbols import TestSymbols
from uclid.test.test_patterns import TestPatterns

if __name__ == "__main__":

    loader = TestLoader()
    tests = [
        loader.loadTestsFromTestCase(test)
        for test in (TestSymbols, TestPatterns)
    ]
    suite = TestSuite(tests)

    runner = TextTestRunner(verbosity=2)
    runner.run(suite)

其中uclid是我的项目和TestSymbolsTestPatternsTestCase的子类。

我已经使用了discover方法和load_tests的过载来实现这一结果在一个(最小的,我认为)的代码行数:

def load_tests(loader, tests, pattern):
''' Discover and load all unit tests in all files named ``*_test.py`` in ``./src/``
'''
    suite = TestSuite()
    for all_test_suite in unittest.defaultTestLoader.discover('src', pattern='*_tests.py'):
        for test_suite in all_test_suite:
            suite.addTests(test_suite)
    return suite

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

上击掌像执行

Ran 27 tests in 0.187s
OK

我尝试了各种办法,但似乎都存在缺陷,或者有化妆的一些代码,这很烦人。但是有linux下的一个方便易办法,那就是简单的通过特定的模式找到每一个测试,然后通过一个调用它们一个。

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

和最重要的是,它肯定工程。

在情况下 打包 库或程序,你不想做到这一点。 setuptools 会为你做它.

使用这种命令,项目的测试必须包裹 unittest 测试通过一种功能,一测试用例类或方法,或者一个模块或包含 TestCase 课程。如果命名的套房是一个模块,模块中有一个 additional_tests() 功能,它是所谓的结果(这必须是一个 unittest.TestSuite)是加入试验可以运行。如果命名是一套包, 任何子和子包是递归增加到总检验套房.

只是告诉它你根检验,包装,如:

setup(
    # ...
    test_suite = 'somepkg.test'
)

并运行 python setup.py test.

文件基于发现可能有问题的Python3,除非你避免的相对进口在你的测试,因为 discover 使用文件导入。即使它支持可选的 top_level_dir, 但我有一些无限递归的错误。所以一个简单的解决方案的一个非封装码是把以下 __init__.py 你的测试软件包(见 load_tests协议).

import unittest

from . import foo, bar


def load_tests(loader, tests, pattern):
    suite = unittest.TestSuite()
    suite.addTests(loader.loadTestsFromModule(foo))
    suite.addTests(loader.loadTestsFromModule(bar))

    return suite

我用的PyDev / LiClipse并没有真正想通了如何运行在从GUI一旦所有的测试。 (编辑:你右击根测试文件夹并选择Run as -> Python unit-test

这是我的当前的解决方法:

import unittest

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

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

我把一个模块调用all这个代码在我的测试目录。如果我运行这个模块从LiClipse一个单元测试,然后所有的测试运行。如果我问只能重复特定的或失败的测试,那么只有那些测试运行。它不与我的命令行测试跑步或者(nosetests)干扰 - 这是忽略

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

这bash脚本会从任何地方在文件系统中执行单元测试蟒蛇test目录,不管你是在什么工作目录。它的工作目录总是如该test目录位于

所有测试中,独立$ PWD

单元测试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文件到您的负担包/内存开销。

下面是通过创建一个包装以运行在命令行测试:

#!/usr/bin/env python3
import os, sys, unittest, argparse, inspect, logging

if __name__ == '__main__':
    # Parse arguments.
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("-?", "--help",     action="help",                        help="show this help message and exit" )
    parser.add_argument("-v", "--verbose",  action="store_true", dest="verbose",  help="increase output verbosity" )
    parser.add_argument("-d", "--debug",    action="store_true", dest="debug",    help="show debug messages" )
    parser.add_argument("-h", "--host",     action="store",      dest="host",     help="Destination host" )
    parser.add_argument("-b", "--browser",  action="store",      dest="browser",  help="Browser driver.", choices=["Firefox", "Chrome", "IE", "Opera", "PhantomJS"] )
    parser.add_argument("-r", "--reports-dir", action="store",   dest="dir",      help="Directory to save screenshots.", default="reports")
    parser.add_argument('files', nargs='*')
    args = parser.parse_args()

    # Load files from the arguments.
    for filename in args.files:
        exec(open(filename).read())

    # See: http://codereview.stackexchange.com/q/88655/15346
    def make_suite(tc_class):
        testloader = unittest.TestLoader()
        testnames = testloader.getTestCaseNames(tc_class)
        suite = unittest.TestSuite()
        for name in testnames:
            suite.addTest(tc_class(name, cargs=args))
        return suite

    # Add all tests.
    alltests = unittest.TestSuite()
    for name, obj in inspect.getmembers(sys.modules[__name__]):
        if inspect.isclass(obj) and name.startswith("FooTest"):
            alltests.addTest(make_suite(obj))

    # Set-up logger
    verbose = bool(os.environ.get('VERBOSE', args.verbose))
    debug   = bool(os.environ.get('DEBUG', args.debug))
    if verbose or debug:
        logging.basicConfig( stream=sys.stdout )
        root = logging.getLogger()
        root.setLevel(logging.INFO if verbose else logging.DEBUG)
        ch = logging.StreamHandler(sys.stdout)
        ch.setLevel(logging.INFO if verbose else logging.DEBUG)
        ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(name)s: %(message)s'))
        root.addHandler(ch)
    else:
        logging.basicConfig(stream=sys.stderr)

    # Run tests.
    result = unittest.TextTestRunner(verbosity=2).run(alltests)
    sys.exit(not result.wasSuccessful())

为了简单起见,请原谅我的非 PEP8 编码标准

然后,您可以创建为您的所有测试通用组件BaseTest类,所以每个测试的只会是这样的:

from BaseTest import BaseTest
class FooTestPagesBasic(BaseTest):
    def test_foo(self):
        driver = self.driver
        driver.get(self.base_url + "/")

要运行,则简单地指定测试作为的命令行参数部分,e.g:

./run_tests.py -h http://example.com/ tests/**/*.py
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top