Pytest单元测试发送电子邮件SMTP



我想在pytest中测试以下功能,而不需要实际创建SMTP服务器并将电子邮件发送到指定地址。

def send_email_investor_owner_occupier(self,user_type,smtp_server):
message=MIMEMultipart()
message['From']=self.email_address
message['To']=self.email_address
suburb_set={suburb for location in user_type.locations for suburb in location.keys()}
suburb_string=','.join(suburb_set)
message['Subject']=f'Investment Properties in {suburb_string} last updated {user_type.date_posted}'
body= f'{user_type.properties} with {user_type.bedrooms} bedrooms, {user_type.bathrooms} bathrooms,{user_type.car_spaces} car spaces, priced between ${user_type.min_price} and ${user_type.max_price} in {suburb_string} last updated {user_type.date_posted}. Key metrics calculated for {user_type.loan_type} {user_type.variable_loan_type if user_type.variable_loan_type!=None else ""} loan with {user_type.lvr/100} lvr for {user_type.loan_term} years with {user_type.mortgage_interest}% interest.'
message.attach(MIMEText(body,"plain"))
message.attach('property_data.csv',self.property_data_io.getvalue(),'text/csv')
with smtplib.SMTP(smtp_server,self.port) as server:
server.starttls()
server.login(self.email_address,self.password)
server.sendmail(self.email_address,self.email_address,message.as_string())
server.quit()

我知道SMTP服务器可以根据https://jingwen-z.github.io/how-to-send-emails-with-python/但我无法用pytest计算出来。如果可能的话,我希望能够在pytest中做到这一点,因为我的所有其他测试都使用该模块。

我不完全确定您在寻找什么,因为您的函数不会返回任何内容。但我想您可以断言哪些函数在send_email_investor_owner_occupier中被调用。

要在pytest中使用mocker,我所做的就是安装pytest mock模块。然后,您可以将测试定义为:

def test_something(mocker):
mocker.patch(foo.bar, return_value=True)
assert foo.bar()

如果你知道如何在unittest中进行mock,那么在pytest中进行嘲讽就很容易了。

假设包含send_email_investor_owner_occupier方法的python模块称为my_email_sender.py,然后对my_email_sender.smtplib.SMTP进行修补。

一种方法是使用补丁装饰器:

from unittest.mock import patch

@patch("my_email_sender.smtplib.SMTP")
def test_send_email_investor_owner_occupier_patch_decorator(smtp_mock):
# call send_email_investor_owner_occupier
# assert like: smtp_mock.assert_called_once_with("server", port)
pass

另一种方法是使用pytest模拟插件进行pytest:

pip install pytest-mock

def test_send_email_investor_owner_occupier_pytest_mock_plugin(mocker):
smtp_mock = mocker.MagicMock(name='smtp_mock')
mocker.patch('my_email_sender.smtplib.SMTP', new=smtp_mock)
# call send_email_investor_owner_occupier
# assert like: smtp_mock.assert_called_once_with("server", port)
pass

这可能看起来有点乏味,但如果你有几个测试来检查邮件发送,并且你想在不复制相同代码的情况下轻松地模拟所有这些测试,你可以将这种方法与pytest fixture混合使用:

import pytest

@pytest.fixture
def smtp_mock(mocker):
smtp_mock = mocker.MagicMock(name='smtp_mock')
mocker.patch('my_email_sender.smtplib.SMTP', new=smtp_mock)
yield smtp_mock


def test_send_email_investor_owner_occupier_pytest_fixture(smtp_mock):
# call send_email_investor_owner_occupier
# assert like: smtp_mock.assert_called_once_with("server", port)
pass

def test_send_email_investor_owner_occupier_pytest_fixture_2(smtp_mock):
# call send_email_investor_owner_occupier
# assert like: smtp_mock.assert_called_once_with("server", port)
pass

def test_send_email_investor_owner_occupier_pytest_fixture_3(smtp_mock):
# call send_email_investor_owner_occupier
# assert like: smtp_mock.assert_called_once_with("server", port)
pass

最新更新