【问题标题】:unittest is not able to discover / run testsunittest 无法发现/运行测试
【发布时间】:2016-05-04 05:53:14
【问题描述】:

somerelated 问题,但没有一个适用。

这是我的目录树:

» 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_backendabc_backend/tests 目录有一个(空的)__init__.py
  • 所有测试模块都是可导入的(见下文)
  • unittest discover 找到了测试,但是相对导入有问题(见下文)
  • nose 能够发现并运行测试,没有问题

我想了解:

  • 为什么我需要将discover 传递给unittest 来强制它发现测试?如果没有 discover 子命令,unittest 会做什么? (我认为 unittest 默认会测试发现)。根据documentation

python -m unittest 相当于 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 发现相对导入有问题

如果我从顶层目录运行它:

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

【问题讨论】:

    标签: python unit-testing python-import nose python-unittest


    【解决方案1】:

    我今天遇到了类似的问题,其实解决方法写在Python API document

    如果找到一个包(包含名为 init.py 的文件的目录),则会检查该包的 load_tests 函数。如果存在,那么它将被称为 package.load_tests(loader, tests, pattern)。即使 load_tests 函数本身调用了 loader.discover,测试发现也会确保在调用期间只检查一次包的测试。

    因此,您只需编写一个 load_tests 函数并在 __init__.py 中注册您的 TestCase 类

    【讨论】:

      【解决方案2】:

      我重现了 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 dir(双关语)放入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) and issubclass(obj, case.TestCase) 返回 False 用于所有模块成员(所以 tests 为空)。

      要使这种特殊的调用方式起作用,您必须做 人们通常在discover 之前所做的事情(除了非标准库 框架):从测试模块(或 可能根据load_tests协议构建测试套件。

      那么,如何

      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 就是这样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-07
        • 2017-10-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多