😎

[Python] unittest.mock チートシート

2024/12/04に公開

Python の unittest.mock に関するチートシート。

※ここでは MagicMockは使わずに patch を使っています。あくまで自分用のチートシートなので、テストコードはかなり簡潔に書いています。

公式のドキュメントはこちら
https://docs.python.org/ja/3/library/unittest.mock.html

from unittest.mock import patch
from path.to.foo import Foo

class TestFoo:
    # patch は何度でも指定できる
    # patch ではなく patch.object を使うことで、参照元にコードジャンプしやすくなる
    @patch.object(Foo, 'do_something')
    @patch.object(Foo, 'check_if_ok')
    def test(
        # 引数の順序は、デコレータで指定した順序の逆になる(Pythonの言語仕様)
        mock_check_if_ok,
        mock_do_something,
    ):
        # 例外を投げさせる
        mock_check_if_ok.side_effect = Exception('NG!')

        # 返り値を設定する
        mock_do_something.return_value = True

        # 1度も実行されていない
        assert mock_do_something.assert_not_called()

        mock_do_something(1,2,3)

        # 実行された
        assert mock_do_something.called

        # 少なくとも1度実行された
        assert mock_do_something.assert_called()

        # 1度だけ実行された
        assert mock_do_something.assert_called_once()

        # 1度だけ実行された(引数指定)
        assert mock_do_something.assert_called_once_with(1,2,3)

        # 最後に実行された際の引数
        args = mock_do_something.call_args.args
        assert args[0] == 1
        
        mock_do_something(key='abc', value=100)

        # N回実行された
        assert mock_do_something.call_count = 2

        # 最後に実行された際のキーワード引数
        kargs = mock_do_something.call_args.kargs
        assert kargs['key'] == 'abc'

        # 今までに以下のように実行されたことがある
        assert mock_do_something.assert_any_call(1,2,3)

        # これまでの実行された引数
        assert mock_do_something.call_args_list == ...

以下、個人的な所感。

  • 自前で MagicMock() するとモックを元に戻す手間が発生するので、 patch デコレータを使うのが良さそう
  • assert_called() よりは called の方がシンプルで良い
  • call_args には最後に実行された引数が入っている、と覚えておく
  • assert_any_call() は便利だけど、名称に any が入っているのでちょっと拒否感がある
  • assert_has_calls() は使うことはあまり無さそう… 実装を変えたらすぐにテストが壊れそう any_order=True を指定しても良いけど
  • call オブジェクトとか気にしたくないので、それを意識させないテストコードにするのが良さそう

Discussion