mock.patch smtplib的正确方法.SMTP



在单元测试中尝试mock.patch对smtplib.SMTP.sendmail的调用。sendmail方法似乎被成功地模拟了,我们可以将其查询为MagicMock,但sendmail模拟的calledcalled_args属性没有正确更新。我似乎没有正确使用补丁。

下面是我正在尝试的一个简化示例:

import unittest.mock
with unittest.mock.patch('smtplib.SMTP', autospec=True) as mock:
import smtplib
smtp = smtplib.SMTP('localhost')
smtp.sendmail('me', 'me', 'hello worldn')
mock.assert_called()           # <--- this succeeds
mock.sendmail.assert_called()  # <--- this fails

此示例生成:

AssertionError: Expected 'sendmail' to have been called.

如果我将补丁更改为smtp.SMTP.sendmail;例如:

with unittest.mock.patch('smtplib.SMTP.sendmail.', autospec=True) as mock:
...

在这种情况下,我可以成功访问mock的called_argscalled属性,但由于允许进行smtplib.SMTP初始化,因此与主机建立了实际的smtp会话。这是单元测试,我更希望没有实际的网络连接。

我今天遇到了同样的问题,忘记了我正在使用上下文,所以只需更改

mock.sendmail.assert_called()

mock.return_value.__enter__.return_value.sendmail.assert_called()

这看起来很混乱,但这是我的例子:

msg = EmailMessage()
msg['From'] = 'no@no.com'
msg['To'] = 'no@no.com'
msg['Subject'] = 'subject'
msg.set_content('content');
with patch('smtplib.SMTP', autospec=True) as mock_smtp:
misc.send_email(msg)
mock_smtp.assert_called()
context = mock_smtp.return_value.__enter__.return_value
context.ehlo.assert_called()
context.starttls.assert_called()
context.login.assert_called()
context.send_message.assert_called_with(msg)

我将dustymugs的帖子标记为答案,但我发现了另一种技术来对依赖于mocks method_calls的调用进行单元测试。

import unittest.mock
with unittest.mock.patch('smtplib.SMTP', autospec=True) as mock:
import smtplib
smtp = smtplib.SMTP('localhost')
smtp.sendmail('me', 'you', 'hello worldn')
# Validate sendmail() was called
name, args, kwargs = smtpmock.method_calls.pop(0)
self.assertEqual(name, '().sendmail')
self.assertEqual({}, kwargs)
# Validate the sendmail() parameters
from_, to_, body_ = args
self.assertEqual('me', from_)
self.assertEqual(['you'], to_)
self.assertIn('hello world', body_)

相关内容

最新更新