You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Mock类方法被调用但未被检测到的问题排查

Python Mock中patch模拟类后,断言实例方法调用失败的问题解决

问题场景

在学习Python Mock时,使用patch模拟Facade类,被测函数main会创建该类实例并调用其install方法。测试中能断言类被成功调用,但install方法的调用断言失败,尽管调试打印显示方法确实被调用,期望assert facadeMock.install.called返回True但实际失败。

被测代码(install/init.py)

from .facade import Facade

def main():
    f = Facade()
    f.install()
    print('jf-debug-> "f.install.called": {value}'.format(
        value=f.install.called))

测试代码(test/install_tests.py)

import os
import sys
# 允许导入目标包
sys.path.insert(0,
                os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from unittest.mock import patch

import install

@patch('install.Facade') # 使用autospec=True也未改变结果
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   # <-------------------- 此处断言失败!

测试输出

============================= 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 ===============================

问题原因

测试参数中的facadeMock是被patch替换后的类本身的Mock对象,而被测函数main()中调用Facade()创建的是该Mock类的实例对象。你断言的facadeMock.install是类级别的方法Mock,实际被调用的是实例对象上的install方法,两者并非同一个Mock对象,因此断言失败。

解决方案

通过facadeMock.return_value获取main()中实际创建的实例Mock,再断言该实例的install方法是否被调用:

修改测试代码中的断言部分:

actualInstance = facadeMock.return_value
assert actualInstance.install.called

完整修改后的测试函数:

@patch('install.Facade')
def test_main_with_links_should_call_facade_install_with_link_true(facadeMock):
    install.main()

    assert facadeMock.called
    actualInstance = facadeMock.return_value
    assert actualInstance.install.called  # 此时断言会成功

补充说明

使用patch模拟类时的核心逻辑:

  • facadeMock是类的Mock,调用它(即Facade())会返回一个实例Mock,该实例Mock被存储在facadeMock.return_value中
  • 实例上的方法调用,必须通过return_value访问对应的方法Mock才能完成正确断言

内容的提问来源于stack exchange,提问作者Jean-Francois

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:41:34