0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonのunittestでデコレータを使ってmockする

Posted at

背景

  • 以前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()
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?