背景
- 以前mockの使い方をまとめました
- "クラスをモックする場合" では
with patch('domain.Class', return_value=None) as mock:
を使ったが、デコレータを使うほうがわかりやすそうななのでメモしておきます
ドキュメント
Mock を使ってパッチしたい場合は、 patch() を1引数で (または patch.object() を2引数で) 使うことができます。mock が自動で生成され、テスト関数/メソッドに渡されます:
class MyTest(unittest.TestCase):
# SomeClassクラスのstatic_methodをモック化し、test_something()に引数で渡している
@patch.object(SomeClass, 'static_method')
def test_something(self, mock_method):
SomeClass.static_method()
mock_method.assert_called_with()
MyTest('test_something').test_something()
次のパターンのように patch デコレータを重ねることができます:
class MyTest(unittest.TestCase):
@patch('package.module.ClassName1')
@patch('package.module.ClassName2')
def test_something(self, MockClass2, MockClass1):
self.assertIs(package.module.ClassName1, MockClass1)
self.assertIs(package.module.ClassName2, MockClass2)
MyTest('test_something').test_something()
デコレータをネストした際、モックは (デコレータを適用する Python の通常の) 順に適用されます。つまり 引数は下から上の順になり、よって上記の例では test_module.ClassName2 が先になります。
実装
from domain import Onemore
import unittest
import requests
from unittest.mock import patch
class Hoge():
def request_api(self, content: str):
r = requests.post(URL, data=content, headers={"Content-Type": "application/json"})
if r.status_code == 200:
print(r.text)
else:
raise Exception(r.text)
class TestHoge(unittest.TestCase):
# @patchデコレータでrequests.postをモック化し、テストの第一引数で渡せる
@patch('requests.post')
def test_request_api(self, mock_post):
# mock_postが指定したmock_responseを返すように設定していく
mock_response = requests.Response()
mock_response.status_code = 500
mock_response._content = b'Server Error'
mock_post.return_value = mock_response
with self.assertRaises(Exception) as context:
Onemore().request_api("テストテキスト")
if __name__ == '__main__':
unittest.main()