简体   繁体   English

使用 unittest.mock 在 python 中修补 SMTP 客户端

[英]Patch SMTP client in python with unittest.mock

I want to mock out the generation of an SMTP client form smtplib .我想模拟smtplib SMTP 客户端的生成。 The following code:以下代码:

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'>

implying that the patch failed.暗示补丁失败。

EDIT: Interestingly Monkey Patching as described here gives the same result.编辑:有趣的是这里描述的猴子补丁给出了相同的结果。

import smtplib
from smtplib import SMTP
from unittest.mock import MagicMock

smtp = MagicMock()
smtplib.SMTP = smtp
print(SMTP, smtp)

I hardly do any patching, but I believe you're patching either too late, or the wrong thing.我几乎不打补丁,但我相信你打补丁要么太晚了,要么是错误的。 SMTP has already been imported, resulting in a direct reference to the original class—it will not be looked up in smtplib anymore. SMTP已经被导入,导致直接引用原始类——它将不再在smtplib查找。 Instead, you'd need to patch that reference.相反,您需要修补该引用。 Let's use a more realistic example, in which you have module.py and test_module.py .让我们使用一个更现实的例子,其中有module.pytest_module.py

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())

As long as you patch in time before a lookup, it does what you want—3 passing tests.只要您在查找之前及时修补,它就会做您想做的事——3 个通过测试。 The very earliest time would be before importing any other modules than unittest .最早的时间是在导入除unittest之外的任何其他模块之前。 Then those modules will not have imported smtplib.SMTP yet.那么这些模块还没有导入smtplib.SMTP More on that here .更多关于这里 It gets tricky though, when your tests are split over multiple modules.但是,当您的测试分为多个模块时,这会变得很棘手。

Patching is inherently dirty.修补本质上是肮脏的。 You're messing with another's internals.你在搞乱别人的内部结构。 To make it work, you have to look on the inside.要让它发挥作用,你必须看看内部。 If the inside changes, tests will break.如果内部发生变化,测试就会中断。 That's why you should consider it a last resort and prefer different means, such as dependency injection.这就是为什么您应该将其视为最后的手段并更喜欢不同的方法,例如依赖项注入。 That's a whole different topic, but in any case, don't rely on patching to prevent messages from going out—also change the configuration!这是一个完全不同的话题,但无论如何,不​​要依赖修补来防止消息外泄——也要更改配置!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM