[英]unittest is not able to discover / run tests
There are some related questions, but none apply.有一些相关的问题,但都不适用。
This is my directory tree:这是我的目录树:
» 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
is not able to find anything: unittest
无法找到任何东西:
top » python -m unittest abc_backend
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Not even from within abc_backend
:甚至不是来自
abc_backend
:
abc_backend » python -m unittest tests
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
What I have already verified:我已经验证过的:
test_whatever
)test_whatever
)unittest.TestCase
unittest.TestCase
abc_backend
and the abc_backend/tests
directories have an (empty) __init__.py
abc_backend
和abc_backend/tests
目录有一个(空) __init__.py
abc_backend/tests
unittest discover
finds the tests, but has problems with relative imports (see below) unittest discover
找到测试,但相对导入有问题(见下文)nose
is able to discover and run the tests, no problems nose
能够发现并运行测试,没有问题I would like to understand:我想明白:
discover
to unittest
to force it to discover the tests?discover
到unittest
,以迫使它发现测试? What does unittest
do without the discover
sub-command?discover
子命令, unittest
做什么? (I thought unittest does test discovery by default). python -m unittest is the equivalent of python -m unittest discover
python -m unittest 相当于 python -m unittest discover
discover
sub-command), why do I have import issues?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
If I run it from the top dir:如果我从顶级目录运行它:
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
If I run it from within abc_backend
:如果我从
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
I reproduced all the problems with CPython 3.5, so my answer should be relevant to both 3.4 and 3.5.我用 CPython 3.5 重现了所有问题,所以我的答案应该与 3.4 和 3.5 相关。
The reason why there are issues with relative imports is that due to specifics of invocations you really do not import abc_backend
package.相对导入存在问题的原因是由于调用的细节,您确实没有导入
abc_backend
包。
First, let's take a look at首先,让我们来看看
top» python3 -m unittest discover abc_backend
When you run tests from top that way, abc_backend
is just not imported.当您以这种方式从顶部运行测试时,不会导入
abc_backend
。 That is because /home/user/top/abc_backend
is added to sys.path instead of /home/user/top
.这是因为
/home/user/top/abc_backend
被添加到 sys.path 而不是/home/user/top
。 To solve this problem, do要解决此问题,请执行
top» python3 -m unittest discover abc_backend -t .
Now, about the in-abc_backend invocation.现在,关于 in-abc_backend 调用。 When you do
当你做
abc_backend» python3 -m unittest discover tests
abc_backend
is not importable, as /home/user/top/abc_backend/tests
dir does not contain abc_backend
package. abc_backend
不可导入,因为/home/user/top/abc_backend/tests
目录不包含abc_backend
包。 This too can be solved with这也可以解决
abc_backend» python3 -m unittest discover tests -t ../
that will correctly put /home/user/top
dir (pun intended) into sys.path
.这将正确地将
/home/user/top
dir(双关语)放入sys.path
。
The -t
(or --top-level-directory
) option sets top level directory of project and defaults to start directory (which is .
by default). -t
(或--top-level-directory
)选项设置项目的顶级目录并默认为开始目录(默认为.
)。 So, what is in sys.path
is important, as that affects imports, which affect test loading, as discovery loads tests using import machinery.因此,
sys.path
很重要,因为它会影响导入,从而影响测试加载,因为发现使用导入机制加载测试。
-m unittest
and -m unittest discover
-m unittest
和-m unittest discover
区别When you do当你做
top» python3 -m unittest abc_backend
in reality you are running unittest/__main__.py
file.实际上,您正在运行
unittest/__main__.py
文件。 There main(module=None)
is invoked, and eventually you get to loadTestsFromModule
that does调用了
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))
As abc_backend/__init__.py
does not contain any test cases, isinstance(obj, type) and issubclass(obj, case.TestCase)
returns False
for all module members (so tests
is empty).由于
abc_backend/__init__.py
不包含任何测试用例,因此isinstance(obj, type) and issubclass(obj, case.TestCase)
为所有模块成员返回False
(因此tests
为空)。
To make this particular way of invocation work, you'll have to do what people usually did in pre- discover
times (aside from non-stdlib frameworks): manually import cases from test modules (or maybe construct test suite according to load_tests
protocol).为了使这种特殊的调用方式起作用,你必须做人们在预
discover
时期通常做的事情(除了非标准库框架):从测试模块手动导入案例(或者可能根据load_tests
协议构建测试套件) .
So, how又怎样
top» python3 -m unittest discover abc_backend
differs?不同?
Basically, differences may be expressed as following conditional:基本上,差异可以表示为以下条件:
if len(argv) > 1 and argv[1].lower() == 'discover':
# -m unittest discover
loader.discover(...)
else:
# -m unittest
loader.loadTestsFromNames(...)
When argv
is ['python3 -m unittest', 'discover', 'abc_backend']
, actual discovery mechanism is used.当
argv
为['python3 -m unittest', 'discover', 'abc_backend']
,使用实际发现机制。 When argv
is ['python3 -m unittest', 'abc_backend']
, loadTestsFromNames
is used, which calls loadTestsFromModule
at some point, and no tests are found.当
argv
为['python3 -m unittest', 'abc_backend']
,使用loadTestsFromNames
,它在某个时刻调用loadTestsFromModule
,并且没有找到测试。 That's the way things are in unittest/main.py
.这就是
unittest/main.py
。
I encountered similar problem today, actually the solution was written in the Python API document :今天遇到了类似的问题,其实解决方案是写在Python API文档中的:
If a package (a directory containing a file named init .py) is found, the package will be checked for a load_tests function.
如果找到一个包(包含名为init .py 的文件的目录),将检查该包的 load_tests 函数。 If this exists then it will be called package.load_tests(loader, tests, pattern).
如果它存在,那么它将被称为 package.load_tests(loader, tests, pattern)。 Test discovery takes care to ensure that a package is only checked for tests once during an invocation, even if the load_tests function itself calls loader.discover.
即使 load_tests 函数本身调用了 loader.discover,测试发现也会确保在调用期间只检查一次包的测试。
Hence, all you need to do is write a load_tests function and register your TestCase classes in __init__.py因此,您需要做的就是编写一个 load_tests 函数并在 __init__.py 中注册您的 TestCase 类
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.