LoginSignup
16
7

More than 3 years have passed since last update.

[Python] pytest-mock使い方メモ

Last updated at Posted at 2020-12-27

インストール

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
exmock/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

16
7
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
16
7