![](/img/trans.png)
[英]How can I use Python MonkeyPatch + Mock to assert that a function was called
[英]How can I mock a function that isn't called by name?
假設我有一個裝飾器,它收集它裝飾的所有函數,以便在將來的某個時候調用。
我的裝飾器.py
class CallLater(object):
funcs = []
def __init__(self, func):
self.funcs.append(func)
@classmethod
def call_now(cls, *args, **kwargs):
for func in cls.funcs:
func(*args, **kwargs)
然后,我在一個模塊中有一個 function,其中一個將由我的裝飾器保存。
我的模塊.py
import logging
from mydecorator import CallLater
logging.basicConfig(level=logging.INFO)
@CallLater
def log_a():
logging.info("A")
@CallLater
def log_b():
logging.info("B")
def log_c():
logging.info("C")
現在,如果我導入mymodule
並調用CallLater.call_now()
,則會調用log_a
和log_b
。 但是假設在測試期間,我希望log_b
被log_c
替換。 我會嘗試用模擬進行替換。
模擬測試.py
import logging
import pytest
from mymodule import log_a, log_c
from mydecorator import CallLater
logging.basicConfig(level=logging.INFO)
pytest_plugins = ('pytest_mock',)
def test_mocking(mocker, caplog):
mocker.patch('mymodule.log_b', log_c)
CallLater.call_now()
logs = [rec.message for rec in caplog.records]
assert logs == ["A", "C"]
但是當我運行pytest
時,我發現我的模擬不起作用。
FAILED mock_test.py::test_mocking - AssertionError: assert ['A', 'B'] == ['A', 'C']
我想'mymodule.log_b'
是錯誤的 mocking 目標,因為它沒有被調用為mymodule.log_b()
,但我不確定在這種情況下使用什么來代替。 任何建議表示贊賞!
這是不可能的,問題是函數在加載時已經分配給列表。 我能看到修補這個的唯一方法是直接修補CallLater.funcs
,這有點尷尬,因為你必須手動替換log_b
為log_c
- 但在這里:
import logging
from unittest import mock
from mymodule import log_c
from mydecorator import CallLater
logging.basicConfig(level=logging.INFO)
def test_mocking(caplog):
funcs = [log_c if f.__name__ == 'log_b' else f for f in CallLater.funcs]
with mock.patch.object(CallLater, 'funcs', funcs):
CallLater.call_now()
logs = [rec.message for rec in caplog.records]
assert logs == ["A", "C"]
請注意,您不能直接與 function (例如f == log_b
)進行比較,因為log_b
是修飾的 function,而不是 ZC1C425268E68385D1AB5074C17A94F1 中保存的CallLater.funcs
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.