2012-04-10 17 views
4

Ich habe einen assert_raised Context-Manager zum Testen geschrieben, der überprüft, ob die erwartete Ausnahme ausgelöst wird, und wenn nicht, wird ein AssertionError ausgelöst. Ich habe auch einen Doptest geschrieben, um das zu testen, aber der Doctest versagt immer und ich bin nicht ganz sicher warum. Hier ist die doctest:Verkettete Ausnahmen in Doctests

>>> for e in [TypeError, ValueError, KeyError]: 
...  with assert_raised(TypeError, ValueError): 
...   print('Raising {}...'.format(e.__name__)) 
...   raise e 
Raising TypeError... 
Raising ValueError... 
Raising KeyError... 
Traceback (most recent call last): 
    ... 
AssertionError: Got 'KeyError', expected 'TypeError, ValueError' 

Und die eigentliche Ausnahme ausgelöst wird:

Traceback (most recent call last): 
    File "<doctest dtlibs.mock.assert_raised[3]>", line 4, in <module> 
    raise e 
KeyError 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "C:\Python32\lib\doctest.py", line 1253, in __run 
    compileflags, 1), test.globs) 
    File "<doctest dtlibs.mock.assert_raised[3]>", line 4, in <module> 
    raise e 
    File "G:\Projects\Programming\dt-tools\dtlibs\dtlibs\mock.py", line 274, in __exit__ 
    raise self._exception(exc_type.__name__) 
AssertionError: Got 'KeyError', expected 'TypeError, ValueError' 

Ich glaube nicht, dass die Umsetzung wichtig ist, aber hier ist es für den Fall, ich etwas falsch mache es (ohne den doctest):

class assert_raised: 

    def __init__(self, *exceptions): 
     self.exceptions = exceptions 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     if exc_type is None: 
      raise self._exception('None') 
     elif self.exceptions and exc_type not in self.exceptions: 
      raise self._exception(exc_type.__name__) 
     return True 

    def _exception(self, got): 
     if len(self.exceptions) == 0: 
      expected = 'an exception' 
     else: 
      expected = ', '.join(e.__name__ for e in self.exceptions) 
     msg = "Got '{}', expected '{}'".format(got, expected) 
     return AssertionError(msg) 

Antwort

4

Doctests hat speziellen Code für das Erheben von Ausnahmen. Als solches wird es erkennen, wenn die Ausgabe eine Ausnahme ist. Damit dies erkannt wird, muss die erwartete Ausgabe mit dem Wort Traceback beginnen. Ihre erwartete Ausgabe beginnt damit nicht, und deshalb erkennt der Doctest die Ausgabe nicht als eine Ausnahme zu erwarten, und daher wird keine Ausnahme erwartet, wenn die Ausnahme kommt, wird es daher fehlschlagen.

Sie können dieses Problem beheben, auf drei Arten:

  1. Befreien des Raising XXXError... Teil der Ausgabe. [Faul]

  2. Implementieren spezielle Ausgangsfilter für doctest die die doctest ermöglicht die Raising XXXError... -Teil [kompliziert]

  3. Stopp mit Doctests für andere Dinge als Test Dokumentation zu ignorieren. [Richtig]

Der obige Code ist eindeutig nicht Beispielcode, wie diesen Kontext-Manager zu verwenden, es ist Code, der die Kontext-Manager funktioniert prüft das. Solche Tests sollten niemals Doptests sein. Doctests sind schmerzhaft und begrenzt und sollten nur zum Testen der Dokumentation verwendet werden.

+1

Danke für die Antwort, das erklärt es! Vielleicht ist meine Dokumentation ein wenig umständlich, aber das ist wirklich nur Beispielcode. Ich habe auch eine Unit-Test-Suite, um das alles zu testen. Wenn ich den Grund kenne, werde ich einfach mein Beispiel vereinfachen. – aquavitae