python中的补丁SMTP客户端与Unittest.mock



我想模拟SMTP客户端表单smtplib的生成。以下代码:

from smtplib import SMTP
from unittest.mock import patch
with patch('smtplib.SMTP') as smtp:
    print(SMTP, smtp)

返回

<class 'smtplib.SMTP'> <MagicMock name='SMTP' id='140024329860320'>

暗示补丁失败。

编辑:如下所述的猴子补丁给出了相同的结果。

import smtplib
from smtplib import SMTP
from unittest.mock import MagicMock
smtp = MagicMock()
smtplib.SMTP = smtp
print(SMTP, smtp)

我几乎没有进行任何修补,但是我相信您正在修补太晚或错误的事情。SMTP已经导入,导致直接引用原始类,它将不再在smtplib中查找。相反,您需要修补该引用。让我们使用一个更现实的示例,其中您具有module.pytest_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。在这里有更多信息。但是,当您的测试在多个模块上分开时,它会变得棘手。

修补本质上是脏的。您正在与他人的内部拼凑在一起。为了使它起作用,您必须在内部看。如果内部变化,测试将破裂。这就是为什么您应该将其视为最后的手段,并且更喜欢不同的手段,例如依赖注入。这是一个完全不同的主题,但是无论如何,不要依靠修补来防止消息出门 - 也更改配置!

最新更新