2

私のカスタム例外クラス:

class MyCustomException(Exception):
    pass

class MyCustomRestException(MyCustomException):

    def __init__(self, status, uri, msg=""):
        self.uri = uri
        self.status = status
        self.msg = msg
        super(MyCustomException, self).__init__(msg)

    def __str__(self):
        return "HTTP ERROR %s: %s \n %s" % (self.status, self.msg, self.uri)

私のテスト

# note: @raises(MyCustomRestException) works by itself
@raises(MyCustomRestException, 'HTTP ERROR 403: Invalid User')
def test_bad_token():
    sc = SomeClass('xxx', account_number)
    result = ec.method_that_generates_exception()

これが鼻が吐き出すものです

12:52:13 ~/sandbox/ec$ nosetests -v
Failure: AttributeError ('str' object has no attribute '__name__') ... ERROR

======================================================================
ERROR: Failure: AttributeError ('str' object has no attribute '__name__')
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/loader.py", line 390, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/local/lib/python2.7/site-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/local/lib/python2.7/site-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/ec/tests/my_client_tests.py", line 16, in <module>
    @raises(MyCustomRestException, 'HTTP ERROR 403: Invalid User')
  File "/usr/local/lib/python2.7/site-packages/nose/tools/nontrivial.py", line 55, in raises
    valid = ' or '.join([e.__name__ for e in exceptions])
AttributeError: 'str' object has no attribute '__name__'

----------------------------------------------------------------------
Ran 1 test in 0.012s

FAILED (errors=1)

それで ...

私の質問は2つあります。

  • このエラーを修正するにはどうすればよいですか?
  • どうすれば(個別にまたは全体として)テストできますか?
    • 例外タイプ
    • Exception.status
    • Exception.uri
    • Exception.msg

解決策:alynnaの助けを借りて(以下)

これはうまくいきます。

def test_bad_token():
    sc = SomeClass('xxx', account_number)

    with assert_raises(MyCustomRestException) as e:
        sc.method_that_generates_exception()

    assert_equal(e.exception.status, 403)
    assert_equal(e.exception.msg, 'Invalid User')
4

2 に答える 2

2

あなたの問題は、@raisesデコレータへの引数がすべて例外クラスであると予想されることだと思います:https ://nose.readthedocs.org/en/latest/testing_tools.html#nose.tools.raises

代わりにassertRaisesが必要な場合があります。ドキュメントには、例外の追加属性をテストするために使用されていることが示されています:http: //docs.python.org/2/library/unittest.html#unittest.TestCase.assertRaises

于 2013-01-23T21:14:31.313 に答える
1

Noseの@raisesデコレータは、例外のクラス以外のチェックをサポートしていません。より多くの引数を渡すことは、より多くのタイプの例外が有効であると解釈されることを許可したいことを意味します。したがって、Noseは、渡した文字列を例外として解釈し、それを見つけることができません__name__。(ドキュメントを参照)

これを修正するには、次のように、カスタム例外に追加のデコレータを実装できます。

from nose.tools import eq_
from functools import wraps

def raises_custom(status=None, uri=None, msg=None):
    assert status or uri or msg, 'You need to pass either status, uri, or msg'
    def decorator(function):
        @wraps(function)
        def wrapper(*args, **kwargs):
            try:
                function(*args, **kwargs)
            except MyCustomException, e:
                def check(value, name):
                    if value:
                        eq_(getattr(exception, name), value)
                check(status, 'status')
                check(uri, 'uri')
                check(msg, 'msg')
            except:
                raise
            else:
                message = "%{} did not raise MyCustomException".format(\
                    function.__name__)
                raise AssertionError(message)
        return wrapper
    return decorator

そしてそれをのように使用し@raises_custom(msg="HTTP ERROR 403: Invalid User")ます。

(私は上記のコードをテストしませんでした、それがどのように見えるかについての大まかな概要を与えることを意図しただけです)

更新:alynnaが提案したように、assertRaisesを使用する方がおそらくクリーンです。特に、関数全体をデコレータでラップするのではなく、例外が発生する特定の場所を特定できれば、より良い結果が得られます。

于 2013-01-23T21:27:20.633 に答える