web-dev-qa-db-ja.com

例外ブロックをテストするために例外を発生させる関数のモック

別の関数(foo)を呼び出す関数(bar)があります。 bar()を呼び出すとHttpErrorが発生する場合、ステータスコードが404の場合は特別に処理し、そうでない場合は再発生します。

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

ここに私の問題を説明する私のコードがあります:

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

モックドキュメント に従いました。これは、Mockインスタンスのside_effectExceptionクラスに設定して、モック関数でエラーを発生させる必要があることを示しています。

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

barMockside_effectを設定すると、期待されるExceptionが発生しないのはなぜですか?変なことをしている場合、exceptブロックでロジックをテストするにはどうすればよいですか?

84
Jesse Webb

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

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

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

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

>>> 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番目の引数から設定する属性です。

100
Martijn Pieters