2013-01-23 2 views
1

Мои пользовательские классы исключений:Как протестировать пользовательское исключение, сообщение с Python Nose

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) 

Итак ...

Мои вопросы два раза:

  • Как исправить эту ошибку?
  • Как я могу проверить (по отдельности или в целом):
    • Исключение Тип
    • 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') 

ответ

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

+0

@raises (MyCustomRestException) работает как MyCustomRestException является классом исключений. – doremi

1

Декоратор Nose @raises не поддерживает проверку чего-либо еще, кроме класса исключения. Передача большего количества аргументов означает, что вы хотите разрешить интерпретации более допустимых типов исключений. Следовательно, Нос интерпретирует строку, которую вы передаете как исключение, и не может найти ее __name__. (См docs)

Чтобы исправить это, вы могли бы реализовать дополнительный декоратор для пользовательского исключения, как:

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").

(я не проверял код выше, просто имел в виду, чтобы дать примерное описание того, как это может выглядеть)

UPDATE: Использование assertRaises, как alynna Предложенная, вероятно, чище, хотя. Особенно лучше, если вы можете определить конкретное место, где должно происходить исключение - в отличие от обертывания всей функции декоратором.

+0

Это довольно круто! Благодарю. – doremi

Смежные вопросы