使用简单的单元测试模拟来修补 SMTP 调用

using simple unittest mock to patch an SMTP call

我正在学习单元测试模拟并试图理解为什么修补对 'smtplib.SMTP' 的调用不是 return 在模拟对象上设置的值。我认为不是,因为断言失败了。

我有一个发送电子邮件的函数的简单定义:

def send(sender, to, subject="None", body="None", server="localhost"):
    message = email.message.Message()
    message['To'] = to
    message['From'] = sender
    message['Subject'] = subject
    message.set_payload(body)

    server = smtplib.SMTP(server)
    try:
        server.sendmail(sender, to, message.as_string())
    finally:
        server.quit()

我有一个包含简单测试函数的单元测试文件:

def test_send():
    with patch('smtplib.SMTP') as mock:
        instance = mock.return_value
        instance.sendmail.return_value = {}
        res = send('x@gmail.com', 'y@gmail.com', 'subject', 'body')
        assert res == {}

据我所知,当调用 'smtplib.SMTP' 的 sendmail 时,该调用应该由 mock 进行修补并且 return 应该是一个空的字典。所以res变量应该设置为{}.

对文件执行 pytest 时,该断言总是失败:

 assert None == {}

我有两个问题:

  1. 我对单元测试的定义有问题吗?
  2. 调试此类问题的好方法是什么。我尝试了 运行 带有 --trace 选项的 pytest,但在单步执行代码时无法捕获 'patching' 时刻。

这里:

res = send('x@gmail.com', 'y@gmail.com', 'subject', 'body')
assert res == {}

您期望 send 会 return 一个值,而该值应该是 {} 的模拟值。然而,您将您的实现定义为不 return 任何东西

def send(sender, to, subject="None", body="None", server="localhost"):
    ...
    try:
        server.sendmail(sender, to, message.as_string())
    ...
    # Doesn't return anything

如果您想查看模拟值,则应回复对 sendmail 调用的 return。

def send(sender, to, subject="None", body="None", server="localhost"):
    ...
    response = None
    try:
        response = server.sendmail(sender, to, message.as_string())
    ....
    return response

运行之后我这边测试成功了。