2016-04-09 7 views
15

Ich versuche, ein Pytest-Plugin zu schreiben, um das Aussehen von bestimmten Ausnahmen anpassen - genauer, Mock-Ausnahmen (Methode aufgerufen wird nicht aufgerufen usw.), weil es eine Menge gibt nutzloses Rauschen in der Rückverfolgung dieser Ausnahmen.Anpassen der Fehlermeldung für bestimmte Ausnahmen in Pytest

Dies ist, was ich bisher habe, das funktioniert, ist aber extrem Hacky:

import pytest 
import flexmock 

@pytest.hookimpl() 
def pytest_exception_interact(node, call, report): 
    exc_type = call.excinfo.type 

    if exc_type == flexmock.MethodCallError: 
     entry = report.longrepr.reprtraceback.reprentries[-1] 
     entry.style = 'short' 
     entry.lines = [entry.lines[-1]] 
     report.longrepr.reprtraceback.reprentries = [entry] 

Ich glaube, ich bin das Richtige mit den hookimpl und Überprüfung des Ausnahmetypen mit einem einfachen tun, wenn Erklärung.

Ich versuchte report.longrepr mit einer einfachen Zeichenfolge zu ersetzen, die auch funktionierte, aber dann verliere ich auf Formatierung (Farben im Terminal).

Als ein Beispiel für die Art der Ausgabe I, hier ist ein Mock-Assertionsfehler verkürzen wollen:

=================================== FAILURES ==================================== 
_______________________ test_session_calls_remote_client ________________________ 

    def test_session_calls_remote_client(): 
     remote_client = mock.Mock() 
     session = _make_session(remote_client) 
     session.connect() 
     remote_client.connect.assert_called_once_with() 
     session.run_action('asdf') 
>  remote_client.run_action.assert_called_once_with('asdff') 

tests/unit/executor/remote_test.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/python-3.6.3/lib/python3.6/unittest/mock.py:825: in assert_called_once_with 
    return self.assert_called_with(*args, **kwargs) 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

_mock_self = <Mock name='mock.run_action' id='139987553103944'> 
args = ('asdff',), kwargs = {}, expected = (('asdff',), {}) 
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f51646269d8> 
actual = call('asdf'), cause = None 

    def assert_called_with(_mock_self, *args, **kwargs): 
     """assert that the mock was called with the specified arguments. 

      Raises an AssertionError if the args and keyword args passed in are 
      different to the last call to the mock.""" 
     self = _mock_self 
     if self.call_args is None: 
      expected = self._format_mock_call_signature(args, kwargs) 
      raise AssertionError('Expected call: %s\nNot called' % (expected,)) 

     def _error_message(): 
      msg = self._format_mock_failure_message(args, kwargs) 
      return msg 
     expected = self._call_matcher((args, kwargs)) 
     actual = self._call_matcher(self.call_args) 
     if expected != actual: 
      cause = expected if isinstance(expected, Exception) else None 
>   raise AssertionError(_error_message()) from cause 
E   AssertionError: Expected call: run_action('asdff') 
E   Actual call: run_action('asdf') 

/opt/python-3.6.3/lib/python3.6/unittest/mock.py:814: AssertionError 
====================== 1 failed, 30 passed in 0.28 seconds ====================== 
+4

Ich verstehe nicht wirklich, was Sie erreichen wollen. Möchten Sie die Tiefe des Stacks reduzieren oder bestimmte Aufrufe entfernen? Können Sie ein Beispiel dafür geben, was Sie bekommen und was Sie erreichen möchten? –

+1

Das Hauptproblem, das ich lösen möchte, ist, dass bei Verwendung von Pythons 'mock' /' unittest.mock'/'flexmock' Bibliotheken, wenn falsche Erwartungen scheitern, eine riesige Stapelverfolgung den Bildschirm überflutet, wenn" Methode X nicht aufgerufen wurde mit Argumenten Y "würde genügen. – Andreas

+6

Haben Sie ein Beispiel dafür, wie die Ausgabe aktuell aussieht und wie sie aussehen soll? – theY4Kman

Antwort

0

Wenn Ihr Ziel ist es, die stacktrace leichter zu lesen, dann können Sie den folgenden Codeblock verwenden um eine benutzerdefinierte Fehlermeldung auszugeben. Diese benutzerdefinierte Fehlermeldung wird am Ende des Stacktrace angezeigt, sodass Sie nicht nach oben scrollen müssen: with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"): pass --> Failed: Expecting ZeroDivisionError Quelle: pytest's documentation. Anstatt also ein Plugin zu erstellen, können Sie die Ausgabe von pytest durch etwas wie grep pipen und die nutzlosen Teile des Stacktrace herausfiltern.
Basierend auf was ich in der Dokumentation gelesen habe, verwenden Sie die richtige Pytest Decorator und Hook-Funktion (pytest_exception_interact). Eine Typüberprüfung auf den Fehler ist jedoch möglicherweise nicht erforderlich. This section of the documentation sagt, dass "Dieser Hook wird nur aufgerufen, wenn eine Ausnahme ausgelöst wurde, die keine interne Ausnahme wie skip.Exception ist."