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

使用unittest.mock.patch打补丁smtplib.SMTP返回值不符合预期问题咨询

问题解答

1. 单元测试存在的问题

你写的测试有两处明显问题:

  • 直接原因是你定义的send函数本身没有任何return语句,不管内部sendmail返回什么值,send执行完默认返回None,这就是断言提示assert None == {}的根源。如果要拿到sendmail的返回值,需要修改send函数显式返回结果,示例修改如下:
def send(sender, to, subject="None", body="None", server="localhost"):
    message = email.message.Message()
    message['To'] = to
    message['From'] = sender
    message['Subject'] = subject
    message.set_payload(body)

    server = smtplib.SMTP(server)
    try:
        # 新增return返回sendmail的执行结果
        return server.sendmail(sender, to, message.as_string())
    finally:
        server.quit()
  • 第二是补丁路径可能不符合mock规则。unittest.mock.patch的核心规则是补丁要打在代码实际引用的位置,而非模块定义的位置。如果你的send函数定义在名为mail_utils的模块中,那么测试时应该补丁mail_utils.smtplib.SMTP,而非直接补丁smtplib.SMTP。因为send函数运行时是从自身所在模块的导入引用里找SMTP类,直接补丁源模块的SMTP不会影响到send函数的调用。

2. 打补丁失效的通用调试方法

  • 查看mock调用统计:在测试调用完目标函数后,打印mock.called、mock.call_count、mock.mock_calls这几个属性,就能直接判断补丁是否生效:如果mock.called为False,说明补丁位置错误,根本没有拦截到目标调用;如果mock_calls里存在预期外的调用记录,也能快速定位配置偏差。
    调试示例:
def test_send():
    with patch('smtplib.SMTP') as mock:
        instance = mock.return_value
        instance.sendmail.return_value = {}
        res = send('x@gmail.com', 'y@gmail.com', 'subject', 'body')
        # 新增调试打印
        print("SMTP是否被调用:", mock.called)
        print("SMTP实例的所有调用记录:", instance.mock_calls)
        assert res == {}
  • 对比对象ID:在send函数中临时加一行打印id(smtplib.SMTP),在测试的patch块中也打印id(mock),如果两个ID不一致,说明补丁没有替换到目标位置,可直接判定是路径写错了。
  • 用异常验证命中:给mock设置side_effect=Exception("命中mock"),如果运行测试时没有抛出这个异常,就说明补丁完全没生效,优先排查路径问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 05:48:03