ものづくりのブログ

うちのネコを題材にしたものづくりができたらいいなと思っていろいろ奮闘してます。

【python】MagicMock を使ってみる

MagicMock を使ってテストコードを作ったので、メモをここに残します。

MagicMock とは

MagicMock は Python の標準ライブラリ unittest.mock に含まれており、テスト対象の関数・メソッド・クラスの動作を模倣(mock)するオブジェクトです。

利用場面

  • 外部APIやDBへのアクセスを実際に行いたくない
  • 副作用(ファイルI/OやHTTP通信など)を避けたい
  • 関数呼び出し回数・引数・戻り値を検証したい

使い方

API 呼び出しをモック

以下のように、api_client が外部 API を呼ぶ想定とします。

def fetch_data(api_client, user_id):
    """APIクライアントからユーザーデータを取得する関数"""
    response = api_client.get_user(user_id)
    return response.get("name", "unknown")

テストでは実際のAPIは呼ばず、MagicMock で代替します。

テストコード
from unittest.mock import MagicMock
from sample import fetch_data

def test_fetch_data_success():

    # --- モックを作成 ---
    mock_api = MagicMock()
    mock_api.get_user.return_value = {"name": "Alice"}

    # --- テスト実行 ---
    result = fetch_data(mock_api, user_id=123)

    # --- 検証 ---
    assert result == "Alice"

    # get_user が正しい引数で1回呼ばれたことを確認
    mock_api.get_user.assert_called_once_with(123)
備考
`MagicMock()` モックオブジェクトを生成
`.return_value` メソッド呼び出し時に返す値を指定
`.assert_called_once_with()` 呼び出し回数や引数を検証
`.side_effect` 呼び出し時に例外発生や異なる戻り値をシミュレートできる

外部 API が例外を返す場合のテスト

def fetch_data(api_client, user_id):
    try:
        response = api_client.get_user(user_id)
        return response["name"]
    except Exception:
        return "error"
テストコード

side_effect を使うことで、例外発生や複数の返り値を順番に返すなどの挙動も再現できます。

from unittest.mock import MagicMock
from sample import fetch_data

def test_fetch_data_error():
    mock_api = MagicMock()
    mock_api.get_user.side_effect = Exception("API Error")

    result = fetch_data(mock_api, user_id=999)

    assert result == "error"
    mock_api.get_user.assert_called_once()

MagicMock の主なメリット

外部依存を排除 DBやAPIを実際に呼ばずにテスト可能
呼び出し履歴の検証 引数・回数・順序などの検証が容易
高速テスト 実際のI/Oをしないので高速
柔軟なカスタマイズ `return_value` / `side_effect` で任意の動作を再現
unittestと自然に統合 pytest や unittest と簡単に組み合わせ可能