setuptools测试隐藏导入错误。如何获得更好的信息?

时间:2009-11-30 09:11:51

标签: python setuptools

在python setuptools中,python setup.py测试运行测试套件。但是,如果我的testsuite中有导入错误,我获得的唯一错误消息是AttributeError抱怨我的测试类丢失了。有没有办法获得更详细的错误消息,所以我可以修复测试套件?

我将通过以下示例更好地解释自己。假设我有一个名为foo的包,用paster重新创建。然后我添加测试

./foo
./foo/__init__.py
./foo/tests
./foo/tests/__init__.py
./foo/tests/mytest.py
./setup.cfg
./setup.py

现在,假设mytest.py包含以下代码

import unittest
class MyTestClass(unittest.TestCase):
    def testFoo(self):
        self.assertEqual(1,1)

这很有效。但是,如果我尝试导入一个不存在的模块

import unittest
import frombiz
class MyTestClass(unittest.TestCase):
    def testFoo(self):
        self.assertEqual(1,1)

这是我获得的错误

Traceback (most recent call last):
  File "setup.py", line 26, in <module>
    test_suite = "foo.tests"
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/distutils/core.py", line 152, in setup
    dist.run_commands()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/distutils/dist.py", line 975, in run_commands
    self.run_command(cmd)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/distutils/dist.py", line 995, in run_command
    cmd_obj.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 121, in run
    self.with_project_on_sys_path(self.run_tests)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 101, in with_project_on_sys_path
    func()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 130, in run_tests
    testLoader = loader_class()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 816, in __init__
    self.parseArgs(argv)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 843, in parseArgs
    self.createTests()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 849, in createTests
    self.module)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 613, in loadTestsFromNames
    suites = [self.loadTestsFromName(name, module) for name in names]
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 587, in loadTestsFromName
    return self.loadTestsFromModule(obj)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 34, in loadTestsFromModule
    tests.append(self.loadTestsFromName(submodule))
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 584, in loadTestsFromName
    parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'mytest'

换句话说,没有引用失败的导入。

4 个答案:

答案 0 :(得分:3)

使用nose。不需要修改代码。只是做:

$ pip install nose
$ nosetests

如果存在ImportError,您将看到它:

ERROR: Failure: ImportError (cannot import name MyModel)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/failure.py", line 37, in runTest
    raise self.exc_class(self.exc_val).with_traceback(self.tb)
  File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/loader.py", line 390, in loadTestsFromName
    addr.filename, addr.module)
  File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/home/garyvdm/bwreport/bwreport/daemon/__init__.py", line 11, in <module>
    from bwreport.models import (
ImportError: cannot import name MyModel

答案 1 :(得分:1)

问题是__import__()的第一个参数必须是模块。当你需要用虚线名称到达某个对象时,你永远不知道哪个部分是模块,什么不是。获取module.subname对象的一种方法是首先尝试将其作为子模块导入,并在失败时使用getattr(module, subname),如unittest那样。这有时会为您AttributeError而不是ImportError。另一种方法是首先尝试getattr(module, subname),只有在失败时才尝试导入。这种方式并不是更好:当有更合适的ImportError时,它有时会为您AttributeError提供。

在这种情况下,最好的unittest可能就是提出自己的异常,说导入和属性查找都失败了。尝试发送此问题的错误报告。

答案 2 :(得分:0)

您可能还想尝试使用Distribute(setuptools的分支)来编写代码,因为setuptools没有得到非常积极的维护。我不知道它会做些什么不同,但值得一试。

答案 3 :(得分:0)

这里的问题是Python ImportError不会告诉你错误实际发生在哪个模块,除非你仔细检查回溯 - 单元测试模块没有做到。无论使用什么工具来运行它,单元测试模块都会遇到同样的问题。

您可能想尝试“鼻子”包 - 它有一个setuptools插件,因此您可以将它添加到您的setup.py中,让它找到并导入您的测试,而不是使用setuptools的默认测试查找器。如果我没记错的话,它会以与unittest不同的方式加载测试代码,并且在这种情况下它可能能够提供更好的错误消息。即使它没有,它可能更容易被添加到鼻子而不是单元测试!