yoshiislandblog.net
元営業の駆け出しアラサーSEが、休日にMACと戯れた際の殴り書きメモ。日々勉強。日々進歩。
pytest_logo_curves

pytestのmonkeypatchで少々はまった話

2022-04-20

pytestのmonkeypatchで少々はまった話

pythonのテストツールpytestのモック機能である便利なmonkeypatchとやらを使ってみた。

参考:公式ドキュメント(How to monkeypatch/mock modules and environments)

monkeypathのテストで、「TypeError: ‘int’ object is not callable」というエラーがでいて、
このエラー文でググると、たくさんヒットするが、「”int”が変数として指定されてしまっているからターミナルを再起動しよう」とかの解決策がヒットし、
今回のケースにマッチしないので、はまっていた。

結果として、monkeypatchの第三引数は、直接指定ではなく、別メソッドの返り値から持ってくることで解決した。
(理由はよくわからず、、)

検証対象のクラス

%  cat myclass.py

class MyClass:

  def func_main(self) -> int:
    return 1

  def func_add(self) -> int:
    return self.func_main() + 2

NGテストコード

%  cat test_myclass_ng.py

from myclass import MyClass

class TestMyClass:

  def test_my_class(self, monkeypatch):
    monkeypatch.setattr(MyClass, 'func_main', 2)
    assert MyClass().func_add() == 4

実行結果
「TypeError: ‘int’ object is not callable」というエラーが出ている

%  pytest test_myclass_ng.py
========================================================== test session starts ==========================================================
platform darwin -- Python 3.9.1, pytest-7.1.1, pluggy-1.0.0
rootdir: /Users/yoshi/monkeypatch_work
collected 1 item

test_myclass_ng.py F                                                                                                              [100%]

=============================================================== FAILURES ================================================================
_______________________________________________________ TestMyClass.test_my_class _______________________________________________________

self = <test_myclass_ng.TestMyClass object at 0x101bbbcd0>, monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x101bbba00>

    def test_my_class(self, monkeypatch):
      monkeypatch.setattr(MyClass, 'func_main', 2)
>     assert MyClass().func_add() == 4

test_myclass_ng.py:8:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <myclass.MyClass object at 0x101bbb6a0>

    def func_add(self) -> int:
>     return self.func_main() + 2
E     TypeError: 'int' object is not callable

myclass.py:8: TypeError
======================================================== short test summary info ========================================================
FAILED test_myclass_ng.py::TestMyClass::test_my_class - TypeError: 'int' object is not callable
=========================================================== 1 failed in 0.04s ===========================================================

OKテストコード

%  cat test_myclass.py

from myclass import MyClass

class TestMyClass:

  def dummy(self):
    return 2

  def test_my_class(self, monkeypatch):
    monkeypatch.setattr(MyClass, 'func_main', self.dummy)
    assert MyClass().func_add() == 4
 

実行結果(成功!)

%  pytest test_myclass.py
========================================================== test session starts ==========================================================
platform darwin -- Python 3.9.1, pytest-7.1.1, pluggy-1.0.0
rootdir: /Users/yoshi/monkeypatch_work
collected 1 item

test_myclass.py .                                                                                                                 [100%]

=========================================================== 1 passed in 0.01s ===========================================================