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

mock.patch装饰器作用范围异常,影响未装饰测试方法排查

问题原因与解决方案

问题原因

Python模块加载后会被缓存到sys.modules中,一旦导入就不会重新加载。第一个测试用@mock.patch("ticketfactory.TicketFactory")替换了ticketfactory模块里的TicketFactory类,同时因为测试中执行了from call_ticket_lambda import lambda_handler,call_ticket_lambda模块内部引用的TicketFactory已经变成了Mock对象。第二个测试里from call_ticket_lambda import TicketFactory拿到的是缓存的Mock版本,而非真实的TicketFactory类,自然会导致断言失败。

解决方案

方法1:测试前手动清理模块缓存

在受影响的测试函数中,先删除相关模块的缓存,再重新导入:

def test_contract_ticket_soap():
    import sys
    # 清理被污染的模块缓存
    for mod in ['call_ticket_lambda', 'ticketfactory']:
        sys.modules.pop(mod, None)
    
    from call_ticket_lambda import TicketFactory
    ticket = TicketFactory.getTicket("CONTRACT")
    
    Logger().info("ticket:" + str(type(ticket)))
    assert isinstance(ticket, ContractTicket) == True

方法2:用自动Fixture统一处理

如果多个测试都存在这个问题,可以用pytest的自动Fixture,在每个测试前后重置模块缓存:

import sys
import pytest

@pytest.fixture(autouse=True, scope="function")
def reset_ticket_modules():
    # 保存原始模块状态
    original_modules = {}
    for mod in ['call_ticket_lambda', 'ticketfactory']:
        if mod in sys.modules:
            original_modules[mod] = sys.modules[mod]
    
    yield
    
    # 恢复或清理模块缓存
    for mod in ['call_ticket_lambda', 'ticketfactory']:
        if mod in original_modules:
            sys.modules[mod] = original_modules[mod]
        else:
            sys.modules.pop(mod, None)

这个Fixture会自动在每个测试执行前保存模块状态,测试结束后恢复,彻底避免测试间的Mock污染。

补充说明

第一个测试中from call_ticket_lambda import lambda_handler的导入时机没问题,但mock.patch的自动撤销仅作用于ticketfactory模块的TicketFactory,无法更新已导入的call_ticket_lambda模块中的引用,所以必须通过清理模块缓存,让call_ticket_lambda重新导入真实的TicketFactory类。

内容的提问来源于stack exchange,提问作者Matthew

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:05:05