LoginSignup
0
0

More than 1 year has passed since last update.

pytest-mockでspy

Posted at

モック対象の振る舞いはそのままで、呼び出し回数や引数、返り値のみをテストで確認したい場合に、spyが使える。

TL;DR

今回は、自作のクラスのメソッドがテスト対象だったので、下記のようにspy。

第1引数にオブジェクト、第2引数にメソッド名の文字列リテラル。返り値は、spyのMockオブジェクト。

spy = mocker.spy(app.Hoge, 'bar')

実装コード

def spy(self, obj: object, name: str) -> unittest.mock.MagicMock:
        """
        Create a spy of method. It will run method normally, but it is now
        possible to use `mock` call features with it, like call count.
        :param obj: An object.
        :param name: A method in object.
        :return: Spy object.
        """

その他メモ

MockerFixtureを使うと、mocker経由で生成したmockなどは、サジェストが有効になるのでちょっと便利。

from pytest_mock import MockerFixture

また最初は、Mock(wraps=)のwrapsオプションでspyのようなことを考えていましたが、spyメソッドを見つけたので、シンプルになりました!spyの実装では、wrapsを活用しているじゃないかと推測してます。下記、実装の一部抜粋。

if asyncio.iscoroutinefunction(method):
            wrapped = functools.update_wrapper(async_wrapper, method)
        else:
            wrapped = functools.update_wrapper(wrapper, method)

        spy_obj = self.patch.object(obj, name, side_effect=wrapped, autospec=autospec)
        spy_obj.spy_return = None
        spy_obj.spy_exception = None
        return spy_obj

検証したコード

import pytest
from pytest_mock import MockerFixture

import app

def test_app_spy(mocker: MockerFixture):
    spy = mocker.spy(app.Hoge, 'bar')
    app.main()

    assert spy.call_count == 1
    # assert spy.call_count == 2
    spy.assert_called_once()
    spy.assert_called_once_with(1, 2, 3)
    assert spy.spy_return == 1 + 2 + 3
    # assert spy.spy_return == 1 + 2 + 4

参考

https://github.com/pytest-dev/pytest-mock#:~:text=not currently tested.-,Spy,-The mocker.spy

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