インストール
poetryを使っていれば簡単です。
poetry add -D pytest-mock
使っていなくても簡単です。けれど、poetryのほうがおすすめです。
pip install pytest-mock
テストの書き方
テストメソッドの引数としてmocker
を指定します。
class MyClassTests:
def test_something(self, mocker):
pass
モックの作り方
モック - Mockを作るには、mocker.Mock
を使ってインスタンスを生成するやり方と、mocker.patch
を使ってダイナミックにMockインスタンスに置き換えていくやり方があります。
題材として、このようなモジュールがあったとします。
exmock
├── __init__.py
├── bar.py
├── foo.py
└── target.py
from .foo import FooClass
from .bar import BarClass
class TargetClass:
def do_something(self, foo: FooClass) -> None:
""" do_foo()の結果をdo_bar()に渡します。 """
bar = BarClass()
bar.do_bar(foo.do_foo())
クラスのモックを作る
foo_mock = mocker.Mock(spec=FooClass)
# foo_mock.do_foo もモックになっています。
specとしてクラスを指定することで、クラスに実在する属性のみが生えるようにします。
生えてきた属性もMock
のインスタンスです。
コンストラクタの戻り値をモックにする
コンストラクタは値を返さないのです表現としておかしいですが、説明の都合上このようにしています。
bar_mock = mocker.Mock(spec=BarClass)
mocker.patch('exmock.target.BarClass', return_value=bar_mock)
テスト対象ファイルexmock/target.pyにあるfrom .bar import BarClass
にあわせて、exmock.target.BarClass
をパッチしています。
メソッドをモック化する
do_bar_mock = mocker.patch.object(BarClass, 'do_bar')
do_bar
メソッドの実装がモック化し、なにもしなくなります。
do_bar
メソッドの動作を変更するには、戻り値のモックを使います。
モックの動作を変更する
生成したモックは、テストにあわせて任意の動きをさせます。
戻り値を設定する
生成したモックのreturn_value
属性に値をセットします。
mymock.return_value = 戻り値
プロパティの戻り値を設定する
直接値をセットすればOKです。
mymock.foo = 戻り値
呼び出されたときに例外を発生させる
生成したモックのside_effect
属性に例外をセットします。
mymock.side_effect = Exception('エラーです')
まるっと置き換える
モック対象の実装をまるっと置き換えます。
def side_effect():
pass
mymock.side_effect = side_effect
モックのテスト
モックに対して、何らかの操作が行われたことをテストします。
1回呼び出されたことをテストする
mymock.assert_called_once()
複数回呼び出されたことをテストする
# pytestを使っている場合です。
assert mymock.call_count == 回数
まったく呼び出されないことをテストする
mymock.assert_not_called()
特定引数で呼び出されたことをテストする
mymock.assert_called_with(特定引数1, 特定引数2, ……)
mymock.assert_called_once_with(特定引数1, 特定引数2, ……) # 1回呼び出される場合
複雑な引数をテストする
args, kwargs = mymock.call_args
# argsやkwargsをテストする
call_args
に、直近の呼び出し引数が入ってます。
args
は、キーワードなし引数が入っているタプルです。kwargs
は、キーワード付き引数が入っているディクショナリです。
検証環境
この記事を書くにあたって使った環境です。
- Python 3.8.2
- Poetry 1.1.4
- pytest-mock 3.4.0
使ったファイルはこちらに置きました。
https://github.com/sengokyu/python-pytest-mock-usage-example