用 unittest.mock 修补 python 中的 SMTP 客户端
Patch SMTP client in python with unittest.mock
我想模拟 SMTP 客户端表单的生成 smtplib
。以下代码:
from smtplib import SMTP
from unittest.mock import patch
with patch('smtplib.SMTP') as smtp:
print(SMTP, smtp)
returns
<class 'smtplib.SMTP'> <MagicMock name='SMTP' id='140024329860320'>
暗示补丁失败
编辑: 有趣的是 Monkey Patching as described here 给出了相同的结果。
import smtplib
from smtplib import SMTP
from unittest.mock import MagicMock
smtp = MagicMock()
smtplib.SMTP = smtp
print(SMTP, smtp)
我几乎不打补丁,但我相信你打补丁太晚了,或者打错了。 SMTP
已经导入,导致直接引用原始 class——它不会再在 smtplib
中查找。相反,您需要修补该参考。让我们使用一个更现实的例子,其中有 module.py
和 test_module.py
.
module.py
:
import smtplib
from smtplib import SMTP # Basically a local variable
def get_smtp_unqualified():
return SMTP # Doing a lookup in this module
def get_smtp_qualified():
return smtplib.SMTP # Doing a lookup in smtplib
test_module.py
import unittest
from unittest import patch
from module import get_smtp_unqualified, get_smtp_qualified
class ModuleTest(unittest.TestCase):
def test_get_smtp_unqualified(self):
with patch('module.SMTP') as smtp:
self.assertIs(smtp, get_smtp_unqualified())
def test_get_smtp_qualified_local(self):
with patch('module.smtplib.SMTP') as smtp:
self.assertIs(smtp, get_smtp_qualified())
def test_get_smtp_qualified_global(self):
with patch('smtplib.SMTP') as smtp:
self.assertIs(smtp, get_smtp_qualified())
只要你在查找之前及时打补丁,它就会如你所愿——3 个通过测试。最早的时间是在导入 unittest
以外的任何其他模块之前。那么这些模块还没有导入 smtplib.SMTP
。更多关于 。但是,当您的测试分为多个模块时,它会变得棘手。
补丁本身就是脏的。你在搞乱别人的内部结构。为了让它发挥作用,你必须从内部看。如果内部发生变化,测试就会中断。这就是为什么您应该将其视为最后的手段并更喜欢不同的方法,例如依赖注入。那是一个完全不同的话题,但无论如何,不要依赖补丁来防止消息外出——还要更改配置!
我想模拟 SMTP 客户端表单的生成 smtplib
。以下代码:
from smtplib import SMTP
from unittest.mock import patch
with patch('smtplib.SMTP') as smtp:
print(SMTP, smtp)
returns
<class 'smtplib.SMTP'> <MagicMock name='SMTP' id='140024329860320'>
暗示补丁失败
编辑: 有趣的是 Monkey Patching as described here 给出了相同的结果。
import smtplib
from smtplib import SMTP
from unittest.mock import MagicMock
smtp = MagicMock()
smtplib.SMTP = smtp
print(SMTP, smtp)
我几乎不打补丁,但我相信你打补丁太晚了,或者打错了。 SMTP
已经导入,导致直接引用原始 class——它不会再在 smtplib
中查找。相反,您需要修补该参考。让我们使用一个更现实的例子,其中有 module.py
和 test_module.py
.
module.py
:
import smtplib
from smtplib import SMTP # Basically a local variable
def get_smtp_unqualified():
return SMTP # Doing a lookup in this module
def get_smtp_qualified():
return smtplib.SMTP # Doing a lookup in smtplib
test_module.py
import unittest
from unittest import patch
from module import get_smtp_unqualified, get_smtp_qualified
class ModuleTest(unittest.TestCase):
def test_get_smtp_unqualified(self):
with patch('module.SMTP') as smtp:
self.assertIs(smtp, get_smtp_unqualified())
def test_get_smtp_qualified_local(self):
with patch('module.smtplib.SMTP') as smtp:
self.assertIs(smtp, get_smtp_qualified())
def test_get_smtp_qualified_global(self):
with patch('smtplib.SMTP') as smtp:
self.assertIs(smtp, get_smtp_qualified())
只要你在查找之前及时打补丁,它就会如你所愿——3 个通过测试。最早的时间是在导入 unittest
以外的任何其他模块之前。那么这些模块还没有导入 smtplib.SMTP
。更多关于
补丁本身就是脏的。你在搞乱别人的内部结构。为了让它发挥作用,你必须从内部看。如果内部发生变化,测试就会中断。这就是为什么您应该将其视为最后的手段并更喜欢不同的方法,例如依赖注入。那是一个完全不同的话题,但无论如何,不要依赖补丁来防止消息外出——还要更改配置!