[英]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.