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
相关产品推荐
相关产品推荐

