別の関数(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_effect
をException
クラスに設定して、モック関数でエラーを発生させる必要があることを示しています。
また、他の関連するStackOverflowのQ&Aも調べましたが、彼らがモックによって引き起こしたり例外を発生させたりするのと同じことをしているようです。
barMock
のside_effect
を設定すると、期待されるException
が発生しないのはなぜですか?変なことをしている場合、except
ブロックでロジックをテストするにはどうすればよいですか?
あなたのモックは例外をうまく発生させていますが、error.resp.status
値がありません。 return_value
を使用するのではなく、Mock
が属性であることをstatus
に伝えるだけです:
barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')
Mock()
への追加のキーワード引数は、結果のオブジェクトの属性として設定されます。
foo
とbar
の定義を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番目の引数から設定する属性です。