wake-up-neo.com

Verspotten einer Funktion zum Auslösen einer Ausnahme zum Testen eines Ausnahmeblocks

Ich habe eine Funktion (foo), die eine andere Funktion aufruft (bar). Wenn das Aufrufen von bar() ein HttpError auslöst, möchte ich es speziell behandeln, wenn der Statuscode 404 ist, andernfalls erneut auslösen.

Ich versuche, einige Unit-Tests für diese foo -Funktion zu schreiben, wobei ich den Aufruf von bar() verspotte. Leider kann ich den verspotteten Aufruf von bar() nicht erhalten, um eine Exception auszulösen, die von meinem except -Block abgefangen wird.

Hier ist mein Code, der mein Problem veranschaulicht:

import unittest
import mock
from apiclient.errors import HttpError


class FooTests(unittest.TestCase):
    @mock.patch('my_tests.bar')
    def test_foo_shouldReturnResultOfBar_whenBarSucceeds(self, barMock):
        barMock.return_value = True
        result = foo()
        self.assertTrue(result)  # passes

    @mock.patch('my_tests.bar')
    def test_foo_shouldReturnNone_whenBarRaiseHttpError404(self, barMock):
        barMock.side_effect = HttpError(mock.Mock(return_value={'status': 404}), 'not found')
        result = foo()
        self.assertIsNone(result)  # fails, test raises HttpError

    @mock.patch('my_tests.bar')
    def test_foo_shouldRaiseHttpError_whenBarRaiseHttpErrorNot404(self, barMock):
        barMock.side_effect = HttpError(mock.Mock(return_value={'status': 500}), 'error')
        with self.assertRaises(HttpError):  # passes
            foo()

def foo():
    try:
        result = bar()
        return result
    except HttpError as error:
        if error.resp.status == 404:
            print '404 - %s' % error.message
            return None
        raise

def bar():
    raise NotImplementedError()

Ich folgte den Mock-Dokumenten , die besagen, dass Sie den side_effect Einer Mock -Instanz auf einen Exception class, damit die verspottete Funktion den Fehler auslöst.

Ich habe mir auch einige andere verwandte Fragen und Antworten zu StackOverflow angesehen, und es sieht so aus, als ob ich das gleiche tue, was sie tun, um zu bewirken, dass Exception von ihrem Mock ausgelöst wird.

Warum führt das Setzen von side_effect Von barMock nicht dazu, dass das erwartete Exception ausgelöst wird? Wie gehe ich vor, wenn ich etwas Seltsames tue, um die Logik in meinem except -Block zu testen?

89
Jesse Webb

Ihr Mock löst die Ausnahme ganz gut aus, aber der Wert error.resp.status Fehlt. Anstatt return_value Zu verwenden, sagen Sie einfach Mock, dass status ein Attribut ist:

barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')

Zusätzliche Schlüsselwortargumente für Mock() werden als Attribute für das resultierende Objekt festgelegt.

Ich habe Ihre Definitionen für foo und bar in ein Modul my_tests Eingefügt, das in der Klasse HttpError hinzugefügt wurde, damit ich es auch verwenden kann und Ihr Test kann dann zum Erfolg geführt werden:

>>> from my_tests import foo, HttpError
>>> import mock
>>> with mock.patch('my_tests.bar') as barMock:
...     barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')
...     result = my_test.foo()
... 
404 - 
>>> result is None
True

Sie können sogar die Zeile print '404 - %s' % error.message Sehen, aber ich glaube, Sie wollten stattdessen error.content Verwenden. das ist jedenfalls das Attribut HttpError(), das aus dem zweiten Argument gesetzt wird.

109
Martijn Pieters