つぶやきテック

日々のつぶやきアウトプット

内部でAPI呼び出しを行う関数の単体テスト【Python】

pytest勉強中

以下のような、「内部でAPI呼び出ししている関数」の単体テストを 書くというケースに最近はじめて出会ったので、備忘メモを残します。

テスト対象コード

import requests

def get_info(**kwargs):
    node = kwargs['auth']
    app = node.get_information('sample')

    app_id = app.get_app_id()

    if app_id is None:
        raise requests.exceptions.HTTPError()

    url = 'https://sample.com/v1/app/' + str(app_id)
    headers = {'Authorization': 'Bearer ' + app.get_sample_key()}
    response = requests.get(url, headers=headers)

    try:
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        raise e

    data = response.json()
    return {'data': {'id': app.id, 'type': data} # 'type': 'sample-status'

テストコード

今回学びになったのは、mock.patchにside_effectという属性があり、 それとモック用の関数を使ってAPI呼び出しの振る舞いを再現できること。

読む人は少ないかもしれませんが、下のような感じでAPI呼び出しを モックしてテストできるようです。

def mocked_requests_get(*args, **kwargs):
    class MockResponse:
        def __init__(self, json_data, status_code):
            self.json_data = json_data
            self.status_code = status_code

        def raise_for_status(self):
            response = requests.Response()
            response.status_code = self.status_code
            try:
                response.raise_for_status()
            except requests.exceptions.HTTPError as e:
                raise e

        def json(self):
            return self.json_data

    if kwargs['headers']['Authorization'] == 'Bearer valid':
        return MockResponse('sample-status', 200)

    return MockResponse('null', 410)

class TestGetInfo(unittest.TestCase)
    @mock.patch('requests.get', side_effect=mocked_requests_get)
    def test_get_info(self, mock_get):
        expected_res = {'data': {'id': app.id, 'type': 'sample-status'}}

        res = get_info(url=url, auth=app.auth)
        assert_equals(res.status_code, 200)
        assert_equals(res.json, expected_res)

    # 異常系は省略

参考サイト