0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

この記事について

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

※あくまで自分用のチートシートなので、テストコードはかなり簡潔に書いています。

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

unittest.mock.MagicMock

特定のクラスなどをモックしたい場合に利用。

# これは実装側
class Foo:
    # クラスのプロパティ
    is_foo = True

    # クラスのメソッド
    def do_something():
        # ...

# これはモック定義
import pytest
from unittest.mock import MagicMock, patch
from path.to.foo import Foo

@pytest.fixture()
def mock_foo():
    foo_mock = MagicMock(spec=Foo)

    foo_mock.do_something = MagicMock(return_value=123)

    with patch('path.to.foo.Foo', return_value=foo_mock):
        # 各テストケースはこの with の中で実行される
        yield foo_mock  # テストケースからモックしたインスタンスを参照するため、yeild に foo_mock を渡す

# これはテストファイル
class TestFoo:
    def test(self, mock_foo):
        # Fooクラスがモックされた状態でのテストとなる
        
        assert mock_foo.do_something.call_count == 1

unittest.mock.patch

クラスの特定のメソッドなどをモックしたい場合に利用。

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 オブジェクトとか気にしたくないので、それを意識させないテストコードにするのが良さそう
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?