pytestのmockerについて

Advent Calendar 2023, pytest, Python

この記事は レコチョク Advent Calendar 2023 の7日目の記事となります。

はじめに

次世代ビジネス推進部の齋藤拓海です。

最近は登山にハマってます。スノボもこれから楽しみです。
最近ハマっているアーティストはpeople 1、キタニタツヤです。

皆さんは普段テストを書いているでしょうか。
自分は現在Pythonで開発をしていて、単体テストはpytest を使用しています。
単体テストを記載していて困るのが、外部APIを使用している部分やDBなどだと思います。
そこでmockが便利なので、今回は紹介したいと思います。

mockの種類

Pythonのmockはpytestのmockとunittestのmockとで2種類あります。

それぞれ特徴を簡単にまとめてみました。

特性/フレームワーク pytest-mock (mocker) unittest.mock (Mock, patch, etc.)
インストール 別途 pytest-mock プラグインをインストールが必要 Python 標準ライブラリの一部として組み込まれている
使用の簡単さ pytest フィクスチャを通じて簡単にアクセスできる デコレータ、コンテキストマネージャ、または手動で Mock をセットアップする
フレームワーク統合 pytestに完全に統合されている unittestと完全に統合されているが、他のテストフレームワークでの使用も可能
APIスタイル よりpytestスタイルに適したインターフェース Python標準のunittestスタイルのインターフェース
コミュニティとの連携 pytestのエコシステムとの強い連携 Python コミュニティ全体からの幅広いサポート
機能 unittest.mockに比べて限られているが、多くのテストケースにおいて十分 より多機能で、複雑なモッキングが可能
学習曲線 pytestに慣れているユーザーにとって簡単 Mockオブジェクトとパッチングの仕組みに慣れる必要あり
柔軟性 pytestフィクスチャと組み合わせることで高い柔軟性を提供 接続されたオブジェクトの視覚化や制御がより詳細に可能

2種類あるとはいえ、pytest-mockはunittestのmockをラップしたものなので、ほとんど同じ感覚で使用できます。

なので、今回はpytest-mockについて話していきます。

mockerの基本:モックの生成と適用方法

mockerを利用すると、スタブ、パッチといったテストダブルを生成し、特定のメソッドや関数の挙動を模倣または制御することが可能となります。

コード内で外部APIを呼び出したり、DBなどミドルウェアと接続したりする部分に使用することで単体テストが可能になります。

スタブの生成と適用

スタブは主に固定の値を返すために使用します。以下の例では、スタブを使用して外部APIからのレスポンスを模倣しています。

パッチの生成と適用

パッチは特定のメソッドや関数の実装を一時的に置き換えるために使用します。
以下の例では、mocker.patchメソッドを使用して’weather.api.get_current_weather’関数の実装を一時的に変更しています。

ほとんど変わりませんがpatchの方が拡張性が高いと感じるので自分はpatchを普段使っています。

mockerの応用:戻り値のカスタマイズ、例外のハンドリング、メソッド呼び出しの確認

mockerは更に、戻り値のカスタマイズ、例外のハンドリング、メソッド呼び出しの確認など、テストの高度な操作も可能にします。

戻り値のカスタマイズ

return_valueを使うと、モックの戻り値を自由に設定することができます。
以下の例では、モックが呼び出されたときに特定の値を返すように設定しています。

例外のハンドリング

side_effectを使うと、モックが呼び出されたときに特定の例外を送出するように設定することも可能です。
これにより、例外のハンドリングのテストが容易になります。

メソッド呼び出しの確認

assert_called_once_withを使うと、モックが期待通りに呼び出されたかどうかを確認することができます。
これにより、コードが想定通りの動作を行っているかを確認できます。

他にもたくさんあります。詳しくは公式ドキュメントをご参照ください。

AIを利用したテストケースの作成

ちょっと物足りないので、テストケース作成をAIに行ってもらいました。

プロンプト

出力結果(try&error済み)

モックを利用したpytestのテストケースを示します。

まず、テスト対象のPythonコードとして以下のような外部APIを呼び出す関数を仮定します。

この関数が外部API(ここでは天気情報API)を呼び出し、レスポンスをjson形式で返すものとします。

この関数のテストをmockerを使って作成します。以下に正常系と異常系のテストケースを示します。

上記のテストケースでは、 requests.getメソッドの挙動をモック化しています。
正常系ではAPIからのレスポンスを模倣し、異常系ではAPIからのエラーレスポンスを模倣しています。

実際に実行してエラーが出たときは下記のプロンプトで修正しました。

このように最近はテストも書いてくれるので、もし苦労していたら活用してみてください。

明日の レコチョク Advent Calendar 2023 は8日目 レコチョクチケット(NFT)のエスノグラフィー調査報告 です。

この記事を書いた人

齋藤拓海
最近書いた記事