python-2.7 - 递归自动测试发现

  显示原文与译文双语对照的内容
0 0

我有一个带有"测试"目录的软件包,我正在存储我的单元测试。 我的软件包看起来像:

.
├── LICENSE
├── models
│ └── __init__.py
├── README.md
├── requirements.txt
├── tc.py
├── tests
│ ├── db
│ │ └── test_employee.py
│ └── test_tc.py
└── todo.txt

我想从我的软件包目录中找到 tests/test_tc.pytests/db/test_employee.py 。 我宁愿不要安装第三方库( nose 或者等) 或者手动构建一个 TestSuite 来运行这个。

当然有一种方法可以告诉 unittest discover 不要停止寻找一次测试? python -m unittest discover -s tests 会找到 tests/test_tc.pypython -m unittest discover -s tests/db 会找到 tests/db/test_employee.py的没有办法找到?

时间:原作者:

0 0

如果你可以在测试中添加 __init__.py 文件,那么可以将 load_tests 函数放在处理你的发现中。

如果测试包名称( 带 __init__.py的目录) 与 Pattern 匹配,那么包将检查'load_tests'函数。 如果存在,则将用加载程序。测试。Pattern 调用它。

如果存在 load_tests,那么发现就不会recurse递归进包,load_tests负责装入包中的所有测试。

我不相信这是最好的方法,但是写这个函数的方法是:

import os
import pkgutil
import inspect
import unittest
# Add *all* subdirectories to this module's path
__path__ = [x[0] for x in os.walk(os.path.dirname(__file__))]
def load_tests(loader, suite, pattern):
 for imp, modname, _ in pkgutil.walk_packages(__path__):
 mod = imp.find_module(modname).load_module(modname)
 for memname, memobj in inspect.getmembers(mod):
 if inspect.isclass(memobj):
 if issubclass(memobj, unittest.TestCase):
 print("Found TestCase: {}".format(memobj))
 for test in loader.loadTestsFromTestCase(memobj):
 print(" Found Test: {}".format(test))
 suite.addTest(test)
 print("=" * 70)
 return suite

非常丑陋,我同意。

首先,将所有子目录添加到包( 文档 )的测试路径。

然后,使用 pkgutil 插件遍历路径,查找包或者模块。

当它找到一个模块成员时,检查模块成员是否是类,如果它们是类,是否是 unittest.TestCase 类。 如果是,类内的测试将加载到测试套件中。

现在,从你的项目 root 中,你可以

python -m unittest discover -p tests

使用 -p Pattern switch 。 如果一切顺利,你将看到我看到的内容,如下所示:

Found TestCase: <class 'test_tc.TestCase'>
 Found Test: testBar (test_tc.TestCase)
 Found Test: testFoo (test_tc.TestCase)
Found TestCase: <class 'test_employee.TestCase'>
 Found Test: testBar (test_employee.TestCase)
 Found Test: testFoo (test_employee.TestCase)
======================================================================
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK

我的两个示例文件中包含了两个测试,testFootestBar,这就是预期的。

更多dig之后,看起来你可以将这里功能指定为:

def load_tests(loader, suite, pattern):
 for imp, modname, _ in pkgutil.walk_packages(__path__):
 mod = imp.find_module(modname).load_module(modname)
 for test in loader.loadTestsFromModule(mod):
 print("Found Tests: {}".format(test._tests))
 suite.addTests(test)

这使用 loader.loadTestsFromModule() 方法而不是使用上面使用的loader.loadTestsFromTestCase() 方法。 它仍然修改 tests 包路径并遍历它,这是我想的关键。

由于我们正在一次向主要 testsuite suite 添加一个 found,输出看起来有点不同:

python -m unittest discover -p tests
Found Tests: [<test_tc.TestCase testMethod=testBar>, <test_tc.TestCase testMethod=testFoo>]
Found Tests: [<test_employee.TestCase testMethod=testBar>, <test_employee.TestCase testMethod=testFoo>]
======================================================================
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK

但是我们仍然得到我们期望的4测试,在两个类中都是。

原作者:
0 0

在挖掘过程中,只要更深的模块保持可以输入,它们就会被发现。 python -m unittest discover 然后,解决方案就是将 __init__.py 文件添加到每个目录中以使它的包装。

.
├── LICENSE
├── models
│ └── __init__.py
├── README.md
├── requirements.txt
├── tc.py
├── tests
│ ├── db
│ │ ├── __init__.py # NEW
│ │ └── test_employee.py
│ ├── __init__.py # NEW
│ └── test_tc.py
└── todo.txt

只要每个目录都有 __init__.pypython -m unittest discover 可以导入相关的test_* 模块。

原作者:
...