setuptoolsテストはインポートエラーを隠します。より良い情報を得るには?

StackOverflow https://stackoverflow.com/questions/1818684

  •  10-07-2019
  •  | 
  •  

質問

python setuptoolsでは、python setup.py testがテストスイートを実行します。ただし、テストスイートでインポートエラーが発生した場合、取得する唯一のエラーメッセージは、テストクラスが見つからないことを訴える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'

つまり、失敗したインポートへの参照はありません。

役に立ちましたか?

解決

問題は、 __ import __()の最初の引数がモジュールでなければならないことです。ドットで区切られた名前のオブジェクトに到達する必要がある場合、どの部分がモジュールであり、何がモジュールではないのかはわかりません。 module.subname オブジェクトを取得する1つの方法は、最初にサブモジュールとしてインポートを試み、失敗した場合は getattr(module、subname) unittest は。これにより、 ImportError ではなく AttributeError が表示される場合があります。これを行う別の方法は、最初に getattr(module、subname)を試行し、失敗した場合にのみインポートを試行することです。この方法の方が優れているわけではありません。 AttributeError がより適切な場合に、 ImportError が表示されることがあります。

この場合、おそらく最良の unittest は、インポートと属性のルックアップの両方が失敗したという独自の例外を発生させることです。この問題のバグレポートを送信してください。

他のヒント

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

配布(setuptools以降のsetuptoolsのフォーク)でコードを試すこともできますあまり積極的に維持されていません)。何か違うことができるかどうかはわかりませんが、一見の価値はあります。

ここでの問題は、unittestモジュールが実行しないトレースバックを慎重に検査しない限り、Python ImportErrorが実際にエラーが発生したモジュールを通知しないことです。 unittestモジュールでも、実行に使用するツールに関係なく、同じ問題が発生します。

&quot; nose&quot;を試してみてください。パッケージ-setuptoolsプラグインが含まれているため、setuptoolsのデフォルトのテストファインダーを使用する代わりに、setup.pyに追加してテストの検索とインポートを行うことができます。正しく思い出せば、unittestとは異なる方法でテストコードをロードし、この場合により良いエラーメッセージを提供できる可能性があります。たとえそうでなくても、おそらくユニットテストよりも鼻に追加する方が簡単でしょう!

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top