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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用unittest.mock在python中修补SMTP客户端相关的知识,希望对你有一定的参考价值。

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

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

意味着补丁失败了。

编辑:有趣的猴子补丁as described here给出相同的结果。

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。更多关于那here。但是,当您的测试分成多个模块时,它会变得棘手。

修补本质上是脏的。你正在搞乱另一个人的内部。为了使它工作,你必须在里面看。如果内部发生变化,测试将会中断。这就是为什么你应该把它作为最后的手段,并喜欢不同的手段,如依赖注入。这是一个完全不同的主题,但无论如何,不​​要依赖修补来防止消息外出 - 也改变配置!

以上是关于使用unittest.mock在python中修补SMTP客户端的主要内容,如果未能解决你的问题,请参考以下文章

使用 unittest.mock.patch 测试 aiohttp 客户端

[Python Modules] unittest.mock

Python 3:unittest.mock如何为特定输入指定不同的返回值?

Python unittest mock:是不是可以在测试时模拟 __init__ 的默认参数的值?

UnitTest, Mock整数类型返回NPE(null)报错

在 python 3.5 中模拟异步调用