テスト作成時に、 クラス属性やモジュール属性、例えば組み込み関数や、テスト対象モジュールにあるインスタンス化されるクラスに対してパッチしたいことがあります。
その様な時は、unittest.mockにあるpatchを使ってパッチできます。
自作したメソッドは公式ドキュメント通りに宣言すれば簡単にパッチを当てられましたが、外部のモジュールにパッチを当てる時に上手くいかずハマった事があるので、正しい書き方を紹介します。
patchの target(第一引数) 間違った書き方
今回はwebフレームワークのDjangoを使った例を紹介します。簡単なコードなので、Djangoを知らなくても問題ありません。
django.core.mailにあるsend_mail()というメールを送信するメソッドの戻り値をpatchを使って0に変更したいとします。私が最初に以下の様なコード書きました。
from unittest.mock import patch
@patch('django.core.mail.send_mail', return_value=0)
def test_mail():
"""メール送信テスト"""
# 以下略
send_mail()の戻り値は正常に配信されたメールの数です (メッセージは1 つしか送信できないため、通常は0か1です)
パッチで戻り値を0にしたかったのですが、1が返されました。
patchのtarget(第一引数) 正しい書き方
mail/views.pyに以下のインポート文が書かれているとします。
from django.core.mail import send_mail
この場合、patchは次の様に書きます。
@patch('mail.views.send_mail', return_value=0)
def test_mail():
"""メール送信テスト"""
# 以下略
上記のようにpatchの第1引数には
”インポートしているファイルへのパス.インポートしたメソッドやクラス名”
と書くと上手くパッチを当てることができます。
最後に
強制的に例外を発生させたり、戻り値を変更したい時にpatchは非常に役立ちます。patchの正しい使い方を覚えて、質の高いunittestを作る役に立てば幸いです。