Python中如何mock非实例方法?实例方法mock正常非实例方法失效如何解决
问题解决:Python unittest mock非实例方法不生效的修复方案
根因分析
你在测试模块头部通过from common.send_mail import send_mail_2的方式直接导入了目标函数,导入操作会在测试模块的作用域内创建一个send_mail_2的变量,直接绑定到原始函数的内存地址。你当前的patch操作修改的是common.send_mail模块下的send_mail_2变量指向,不会影响测试模块内已经完成绑定的函数引用,因此mock不会生效。
而实例方法的mock能生效是因为你每次调用都是先实例化Email类,走的是common.send_mail模块下的类定义,因此patch原模块的类方法可以命中。
修复方案
提供两种可行的修改方式,任选其一即可:
方案1:修改patch路径,指向测试模块内导入的函数
直接patch测试模块作用域内已经导入的send_mail_2变量,替换后调用时就会走mock逻辑,修改后的测试代码如下:
import unittest from unittest.mock import patch from common.send_mail import Email, send_mail_2 class Test(unittest.TestCase): # 此处改为patch当前测试模块内的send_mail_2引用 @patch('common.test_mocking.send_mail_2') @patch('common.send_mail.Email.send_mail') def test_send_email(self, mock_instance, mock_non_instance): mock_instance.return_value = 1 mock_non_instance.return_value = 1 res = Email().send_mail() assert res == 1 res1 = send_mail_2() assert res1 == 1
方案2:调整导入和调用方式,通过模块访问目标函数
不单独导入send_mail_2,改为导入整个send_mail模块,调用时通过模块名访问函数,此时patch原模块的函数即可生效:
import unittest from unittest.mock import patch from common import send_mail # 导入整个模块,不单独导入函数 class Test(unittest.TestCase): @patch('common.send_mail.send_mail_2') @patch('common.send_mail.Email.send_mail') def test_send_email(self, mock_instance, mock_non_instance): mock_instance.return_value = 1 mock_non_instance.return_value = 1 res = send_mail.Email().send_mail() assert res == 1 res1 = send_mail.send_mail_2() # 通过模块调用函数 assert res1 == 1
注意事项
unittest的patch装饰器参数顺序和函数接收的mock参数顺序相反:越靠近测试函数的patch装饰器,对应的mock参数越靠前,你当前代码的参数顺序是正确的,无需调整。
内容的提问来源于stack exchange,提问作者Dhivakhar Venkatachalam
相关产品推荐
相关产品推荐

