2024年8月25日日曜日

Python の unittest mock を使って requests の get をモックする方法

Python の unittest mock を使って requests の get をモックする方法

概要

unittest の mock を使って request.get をモックする方法を紹介します
更に pytest の fixture を使います

環境

  • macOS 11.7.10
  • Python 3.11.6
  • requests 2.32.3
  • pytest 8.2.2

サンプルコード

httpbin にリクエストしてその結果を dict に変換します

import requests


class HttpBinClient:
    def __init__(self) -> None:
        pass

    def fetch(self) -> requests.Response:
        return requests.get("https://httpbin.org/get")

    def to_json(self, response: requests.Response) -> dict:
        return response.json()


if __name__ == "__main__":
    hbc = HttpBinClient()
    res = hbc.fetch()
    print(hbc.to_json(res))

テストコード

httpbin のレスポンスには url というフィールドがありアクセスした url が含まれているのでそれが正しいかテストするコードを作成します

  • vim test/test_app.py
from app import HttpBinClient


class TestHttpBinClient:
    def test_fetch(self):
        hbc = HttpBinClient()
        response = hbc.fetch()
        result = hbc.to_json(response)
        assert result["url"] == "https://httpbin.org/get"
  • pipenv run pytest -s test/test_app.py

これで実行すると問題なく成功します
今回はこのテストにおいて requests.get で実際に外部にリクエストする部分をモックします

モックする conftest

conftest を使ってモックします
ポイントは requests.get に patch を当てつつ更にレスポンスのオブジェクトを正しく生成することです

  • vim test/conftest.py
from unittest.mock import Mock, patch

import pytest
import requests


@pytest.fixture(autouse=True)
def mock_request_get():
    with patch("requests.get") as m:
        # requests のレスポンスオブジェクトを生成、理由は requests.get の返り値の型が requests.Response なため
        response = requests.Response()
        # json 関数をモックします、関数をモックする場合は Mock クラスを使って return_value でその関数の返り値を指定します
        response.json = Mock(return_value={"url": "http://localhost"})
        response.status_code = 200
        # あとはモックオブジェクト (requests.get) の返り値に対してモックしたレスポンスを割り当てます
        m.return_value = response
        # 今回は with 句を使って patch しているため yield でモックオブジェクトを指定しなければいけません
        yield m

動作確認

  • pipenv run pytest -s test/test_app.py

で先程成功したテストが失敗することを確認します
モックでは実際にアクセスしないのでモックに指定した偽の返り値になるためエラーになります

最後に

pytest + unitest mock で requests.get をモックしていました
同じように post などもモックできます

0 件のコメント:

コメントを投稿