[英]python - mock - class method mocked but not reported as being called
在這里學習 python 模擬。 我需要一些幫助來了解補丁在 mocking 和 class 時是如何工作的。
在下面的代碼中,我模擬了一個 class。被測試的 function 接收模擬並在其上調用 function。 在我的斷言中,class 被成功調用,但 function 被報告為未被調用。
我添加了調試打印以查看測試中的 function 中的內容,並報告為已調用。
我的期望是斷言assert facadeMock.install.called應該是真的。 為什么它沒有被報告為已調用,我該如何實現?
謝謝你。
安裝/__init__.py
from .facade import Facade
def main():
f = Facade()
f.install()
print('jf-debug-> "f.install.called": {value}'.format(
value=f.install.called))
測試/install_tests.py
import os
import sys
# allow import of package
sys.path.insert(0,
os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from unittest.mock import patch
import install
@patch('install.Facade') # using autospec=True did not change the result
def test_main_with_links_should_call_facade_install_with_link_true(facadeMock):
install.main()
assert facadeMock.called
assert facadeMock.install is install.Facade.install
assert facadeMock.install.called # <-------------------- Fails here!
output:
============================= test session starts ==============================
platform linux -- Python 3.10.6, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/jfl/ubuntu-vim, configfile: pytest.ini
collected 1 item
test/install_tests.py jf-debug-> "f.install.called": True
F
=================================== FAILURES ===================================
________ test_main_with_links_should_call_facade_install_with_link_true ________
facadeMock = <MagicMock name='Facade' id='140679041900864'>
@patch('install.Facade')
def test_main_with_links_should_call_facade_install_with_link_true(facadeMock):
install.main()
assert facadeMock.called
assert facadeMock.install is install.Facade.install
> assert facadeMock.install.called
E AssertionError: assert False
E + where False = <MagicMock name='Facade.install' id='140679042325216'>.called
E + where <MagicMock name='Facade.install' id='140679042325216'> = <MagicMock name='Facade' id='140679041900864'>.install
test/install_tests.py:21: AssertionError
=========================== short test summary info ============================
FAILED test/install_tests.py::test_main_with_links_should_call_facade_install_with_link_true - AssertionError: assert False
============================== 1 failed in 0.09s ===============================
[編輯]
感謝@chepner 和@Daniil Fajnberg 的評論。 我找到了問題的原因。
問題可以減少在: install/__init__.py
在main() 中調用Facade() 時接收到一個Facade 的實例。 此實例與測試參數中收到的實例不同。 它們是不同的實例。
要檢索在 main() 中接收到的實例,請執行以下操作:
actualInstance = facadeMock.return_value
assert actualInstance.install.called
它有效!
謝謝你。 這確實有助於我理解 python 中模擬的工作原理。
[/編輯]
我找到了解決您問題的方法; 它是經驗性的,但它有效。
為了通過你的測試,我修改了它,如下所示:
@patch('install.Facade') # using autospec=True did not change the result
def test_main_with_links_should_call_facade_install_with_link_true(facadeMock):
install.main()
assert facadeMock.called
assert facadeMock.install is install.Facade.install
#assert facadeMock.install.called # <-------------------- Fails here!
install_called = False
for call_elem in facadeMock.mock_calls:
if call_elem[0] == "().install":
install_called = True
break
assert install_called == True
facadeMock
和f
facadeMock
是在測試代碼中創建的模擬 object ,在測試期間生產代碼使用它通過指令創建模擬 object f
:
f = Facade()
在生產代碼中, f
是一個 mock object(即 class Mock
的一個實例),因為它是由 Mock object Facade
創建的,它正是facadeMock
。
但是f
和facadeMock
是 class Mock
的兩個不同實例。
下面我展示了facadeMock
、 Facade
和f
的 id 值:
facadeMock = <MagicMock name='Facade' id='140449467990536'>
Facade = <MagicMock name='Facade' id='140449467990536'>
f = <MagicMock name='Facade()' id='140449465274608'>
facadeMock
和Facade
的 id 與f
的 id 不同。
當您的測試代碼被執行時, function install.main()
執行會導致模擬 object facadeMock
的屬性mock_calls
的定義。
該屬性是復雜元素的列表。
如果您檢查每個元素的第一個字段(我的意思是 position 0 中的字段),您可以找到被調用的模擬方法的名稱。
在您的情況下,您必須找到install
並為此必須查找().install
。 因此,我的測試檢查了mock_calls
的所有元素,並且僅當().install
被發現時才設置變量install_called=True
。
我希望這個答案可以幫助你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.