简体   繁体   English

unittest 无法发现/运行测试

[英]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:我已经验证过的:

  • my test methods are properly named ( test_whatever )我的测试方法被正确命名( test_whatever
  • my testcases extend unittest.TestCase我的测试用例扩展了unittest.TestCase
  • the abc_backend and the abc_backend/tests directories have an (empty) __init__.py abc_backendabc_backend/tests目录有一个(空) __init__.py abc_backend/tests
  • all test modules are importable (see below)所有测试模块都是可导入的(见下文)
  • 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:我想明白:

  • why do I need to pass discover to unittest to force it to discover the tests?为什么我需要通过discoverunittest ,以迫使它发现测试? What does unittest do without the discover sub-command?如果没有discover子命令, unittest做什么? (I thought unittest does test discovery by default). (我认为 unittest 默认情况下会测试发现)。 According to the documentation :根据文档

python -m unittest is the equivalent of python -m unittest discover python -m unittest 相当于 python -m unittest discover

  • once the tests are discovered (by forcing the discover sub-command), why do I have import issues?一旦发现测试(通过强制discover子命令),为什么我有导入问题?

Test modules are importable测试模块是可导入的

» 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 has problems with relative imports unittest 发现相对导入有问题

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 相关。

Relative import issues相对进口问题

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很重要,因为它会影响导入,从而影响测试加载,因为发现使用导入机制加载测试。

Difference between -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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM