関数をモックして例外を発生させ、exceptブロックをテストする


118

foo別の関数(bar)を呼び出す関数()があります。呼び出しでbar()が発生したHttpError場合、ステータスコードが404の場合は特別に処理し、それ以外の場合は再発生させます。

このfoo関数の周りにいくつかの単体テストを書いて、への呼び出しを模倣しようとしていますbar()。残念ながら、ブロックでbar()キャッチされた例外を発生させるためにモックされた呼び出しを取得できませんexcept

これが私の問題を説明する私のコードです:

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()

私は続いモックドキュメントあなたが設定しなければならないことを言うside_effectMockにインスタンスをException嘲笑関数raiseにエラーを持っているクラスを。

他の関連するStackOverflowのQ&Aも確認しましたが、彼らが引き起こしているのと同じことをしていて、モックによって例外が発生しているようです。

なぜ期待値が発生しないという設定になっているside_effectのですか?奇妙なことをしている場合、ブロック内のロジックをテストするにはどうすればよいですか?barMockExceptionexcept


あなたの例外発生しいると確信していますが、resp.statusそこでコードをどのように設定しているかはわかりません。どこHTTPErrorから来たの?
Martijn Pieters

@MartijnPieters HttpErrorは、GAEで使用するGoogleのapiclientlibで定義されたクラスです。これ__init__はparamsで定義されている(resp, content)ため、適切なステータスコードを指定して、応答のモックインスタンスを作成しようとしました。
Jesse Webb

そう、それがこのクラスです。ただし、その場合は使用する必要はありませんreturn_value呼ばれてrespいません。
Martijn Pieters

1
使用せずにコードを再試行しHttpError、代わりに通常のExceptionインスタンスのみを使用してみました。これは完全に機能します。これは、HttpErrorインスタンスの構成方法に何らかの関係がある必要があることを意味します。おそらくMock、応答のインスタンスを作成する方法に関連しています。
Jesse Webb

回答:


141

あなたのモックは例外をうまく上げていますが、error.resp.status値がありません。を使用するのreturn_valueではなく、Mockそれstatusが属性であることを伝えてください。

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

追加のキーワード引数Mock()は、結果のオブジェクトの属性として設定されます。

私はあなたfoobar定義をmy_testsモジュールに入れ、HttpErrorクラスに追加して私もそれを使用できるようにし、テストを成功させることができます:

>>> 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

print '404 - %s' % error.messageラインのランも確認できますerror.contentが、代わりにそこで使用したいと思います。それHttpError()はとにかく、2番目の引数からの属性セットです。


2
これside_effectが重要な部分です
ダニエルバトラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.