这是我的目录树:
» tree abc_backend
abc_backend/
├── backend_main.py
├── FundDatabase.db
├── healthcheck.py
├── __init__.py
├── init.py
├── portfolio.py
├── private.py
├── __pycache__
├── questionnaire.py
├── recurring.py
├── registration.py
├── tests
│ ├── config.py
│ ├── __init__.py
│ ├── __pycache__
│ ├── test_backend.py
│ ├── test_healthcheck.py
│ └── test_private.py
├── trading.py
├── Users.db
├── VERSION
└── visualisation.py
unittest
找不到任何东西:
top » python -m unittest abc_backend
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
甚至不在 abc_backend
中:
abc_backend » python -m unittest tests
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
我已经验证过的:
- 我的测试方法已正确命名 (
test_whatever
) - 我的测试用例扩展
unittest.TestCase
abc_backend
和abc_backend/tests
目录有一个(空的)__init__.py
- 所有测试模块都是可导入的(见下文)
unittest discover
找到测试,但相对导入有问题(见下文)nose
能够发现并运行测试,没有问题
我想了解:
- 为什么我需要将
discover
传递给unittest
以强制它发现测试?如果没有discover
子命令,unittest
会做什么? (我认为 unittest 默认情况下会进行测试发现)。根据documentation :
python -m unittest is the equivalent of python -m unittest discover
- 一旦发现测试(通过强制执行
discover
子命令),为什么会出现导入问题?
测试模块是可导入的
» python
Python 3.4.3 (default, Oct 14 2015, 20:28:29)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import abc_backend.tests
>>> import abc_backend.tests.test_private
>>> import abc_backend.tests.test_healthcheck
>>> import abc_backend.tests.test_backend
unittest discover 相对导入有问题
如果我从顶层目录运行它:
top » python -m unittest discover abc_backend
======================================================================
ERROR: tests.test_private (unittest.loader.ModuleImportFailure)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python3.4/unittest/case.py", line 58, in testPartExecutor
yield
File "/usr/lib/python3.4/unittest/case.py", line 577, in run
testMethod()
File "/usr/lib/python3.4/unittest/loader.py", line 32, in testFailure
raise exception
ImportError: Failed to import test module: tests.test_private
Traceback (most recent call last):
File "/usr/lib/python3.4/unittest/loader.py", line 312, in _find_tests
module = self._get_module_from_name(name)
File "/usr/lib/python3.4/unittest/loader.py", line 290, in _get_module_from_name
__import__(name)
File "/foo/bar/abc_backend/tests/test_private.py", line 6, in <module>
from .. import init
ValueError: attempted relative import beyond top-level package
如果我从 abc_backend
中运行它:
abc_backend » python -m unittest discover tests
======================================================================
ERROR: test_private (unittest.loader.ModuleImportFailure)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python3.4/unittest/case.py", line 58, in testPartExecutor
yield
File "/usr/lib/python3.4/unittest/case.py", line 577, in run
testMethod()
File "/usr/lib/python3.4/unittest/loader.py", line 32, in testFailure
raise exception
ImportError: Failed to import test module: test_private
Traceback (most recent call last):
File "/usr/lib/python3.4/unittest/loader.py", line 312, in _find_tests
module = self._get_module_from_name(name)
File "/usr/lib/python3.4/unittest/loader.py", line 290, in _get_module_from_name
__import__(name)
File "/foo/bar/abc_backend/tests/test_private.py", line 6, in <module>
from .. import init
SystemError: Parent module '' not loaded, cannot perform relative import
最佳答案
我用 CPython 3.5 重现了所有问题,所以我的回答应该 与 3.4 和 3.5 相关。
相对导入问题
相对进口存在问题的原因是由于
您确实没有导入 abc_backend
包的调用细节。
首先我们来看
top» python3 -m unittest discover abc_backend
当您以这种方式从顶部运行测试时,abc_backend
不会被导入。
这是因为 /home/user/top/abc_backend
被添加到 sys.path
/home/user/top
。为了解决这个问题,做
top» python3 -m unittest discover abc_backend -t .
现在,关于 in-abc_backend 调用。当你做的时候
abc_backend» python3 -m unittest discover tests
abc_backend
不可导入,如 /home/user/top/abc_backend/tests
dir 不包含 abc_backend
包。这也可以解决
abc_backend» python3 -m unittest discover tests -t ../
这将正确地将 /home/user/top
目录(双关语)放入 sys.path
。
-t
(或--top-level-directory
)选项设置顶级目录
项目的起始目录(默认为 .
)。
因此,sys.path
中的内容很重要,因为它会影响导入,这
影响测试加载,因为发现加载测试使用进口机器。
-m unittest
和-m unittest discover
的区别
当你做的时候
top» python3 -m unittest abc_backend
实际上您正在运行 unittest/__main__.py
文件。那里
main(module=None)
被调用,最终你得到
loadTestsFromModule
这样做
tests = []
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, type) and issubclass(obj, case.TestCase):
tests.append(self.loadTestsFromTestCase(obj))
由于 abc_backend/__init__.py
不包含任何测试用例,
isinstance(obj, type) 和 issubclass(obj, case.TestCase)
返回
False
对于所有模块成员(因此 tests
为空)。
要使这种特殊的调用方式起作用,您必须这样做
人们在 discover
之前通常做的事情(除了非标准库
框架):从测试模块手动导入案例(或
也许根据load_tests
协议(protocol)构建测试套件)。
那么,如何
top» python3 -m unittest discover abc_backend
不同吗?
基本上,差异可以表示为以下条件:
if len(argv) > 1 and argv[1].lower() == 'discover':
# -m unittest discover
loader.discover(...)
else:
# -m unittest
loader.loadTestsFromNames(...)
当argv
为['python3 -m unittest', 'discover', 'abc_backend']
时,
使用实际发现机制。当argv
为['python3 -m unittest', 'abc_backend']
时,
使用了loadTestsFromNames
,它在某个时候调用了loadTestsFromModule
,但没有找到任何测试。
这就是 unittest/main.py
中的内容。
关于python - unittest 无法发现/运行测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35034664/