2010-01-06 2 views
0

У меня возникает странная проблема при использовании unittest.assertRaises. При выполнении приведенного ниже кода я получаю следующий результат:assertRaises просто улавливает базовое исключение

E 
====================================================================== 
ERROR: testAssertRaises (__main__.Test) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "C:\home\python_test\src\derived.py", line 29, in testAssertRaises 
    self.assertRaises(MyError, self.raiser.raiseMyError) 
    File "C:\Programme\Python26\lib\unittest.py", line 336, in failUnlessRaises 
    callableObj(*args, **kwargs) 
    File "C:\home\python_test\src\derived.py", line 15, in raiseMyError 
    raise MyError("My message") 
MyError: 'My message' 

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

FAILED (errors=1) 

Исправлено исключение, но тест не срабатывает! Если я поймаю BaseError, тест пройдет успешно.

Как-то это похоже на проблему с областью unittest, которая не может видеть класс исключений MyError. Может ли кто-нибудь объяснить это? Есть ли способ обхода?

Я тестирую следующий код Python, который представляет собой реализацию для динамического построения объектов по именам классов.

Это базовый модуль "bases.py":

class BaseClass(object): 

    @staticmethod 
    def get(className): 
     module = __import__("derived", globals(), locals(), [className]) 
     theClass = getattr(module, className) 
     return theClass() 


class BaseError(Exception): 

    def __init__(self, msg): 
     self.msg = msg 

    def __str__(self): 
     return repr(self.msg) 

Это модуль для тестирования, "derived.py":

import unittest 

from bases import BaseError 
from bases import BaseClass 


class MyErrorRaiser(BaseClass):  

    def raiseMyError(self): 
     raise MyError("My message") 


class MyError(BaseError): 
    ''' 
    ''' 


class Test(unittest.TestCase): 

    def setUp(self): 
     self.raiser = BaseClass.get("MyErrorRaiser") 

    def testAssertRaises(self): 
     self.assertRaises(MyError, self.raiser.raiseMyError) 


if __name__ == "__main__": 
    unittest.main() 

ответ

1

Когда вы запустите файл производным.py, он запускается как модуль __main__ (поскольку вы запускаете его напрямую, а не импортируете его). Когда вы позже импортируете его явно, создается другая копия модуля, на этот раз под именем derived. Таким образом, __main__.MyError - это не то же самое, что и derived.MyError, и исключение не поймано.

+0

А, это имеет смысл. Любая идея, как лучше реализовать это? Я уже заметил, что он работает, если переместить исключения в отдельный модуль. – desolat

+0

Перемещение исключений устранит эту проблему, но у вас все еще есть две разные копии одного и того же модуля, и позже могут возникнуть другие проблемы. Вам нужно как-то убедиться, что основной модуль не будет импортирован другим модулем. Я не знаю, зачем вам нужен метод «BaseClass.get», поэтому я не могу сказать вам, как его улучшить, за исключением того, чтобы не называть его в модульном тесте. – interjay

0

Проблема заключается в том, вероятно, что ваш метод BaseClass.get() возвращает вам другой класс. Кстати, этот метод ужасен сам по себе, интересно, почему вы это делаете.

+0

Да, это его цель. Это всего лишь упрощенный пример полного кода, который является своего рода абстрактной фабрикой для создания экземпляров реализаций интерфейса по их имени. В любом случае, я был бы признателен, если бы вы помогли мне с моей проблемой или обеспечили лучшую реализацию, а не просто напыщенность. – desolat

+0

«Просто напыщенная речь» ?! Я указал, что проблема, вероятно, в том, что 'BaseClass.get()' возвращает вам другой класс, чем тот, который вы передаете 'assertRaises'. 'assertRaises' не виноват.Теперь, если вам не нравятся люди, комментирующие ваш код или стиль дизайна, пожалуйста, не публикуйте вопросы программирования в Интернете. –

+0

Если бы вы запустили код выше, вы бы увидели, что это не проблема. Если у вас нет проблемы, не отвечайте на вопросы, которые вы не понимаете. См. Принятый ответ о том, как это сделать. – desolat

2

В mentioned, вопрос модули __main__ и производные не одно и то же; этот ответ о том, как вы это исправите.

Не следует код модуля микширования и код сценария. Начать думать о if __name__ == "__main__" код как взломать. (Это по-прежнему очень удобно порой, и я часто использую его для отладки и т. Д., Но вид это как взломать, чтобы вы всегда получали небольшое умственное подталкивание, пишущее его.) Новый скрипт, который затем запускал все, был бы простым (и никогда не импортировались):

#!/usr/bin/env python 
import derived 
import sys 
sys.exit(derived.main(sys.argv[1:])) 

Или с различными отличиями по личным предпочтениям. Просто убедитесь, что вы добавили output.main, чтобы делать то, что хотите.

Я также видел другой хак, который является менее распространенным, на верхней из derived.py:

import sys 
if __name__ == "__main__": 
    import derived # import the same module under its "correct" name 
    sys.exit(derived.main(sys.argv[1:])) 

Хотя расточительно в разборе тот же код дважды, это самодостаточный в обмен.