简体   繁体   English

Pytest 单元测试发送 Email SMTP

[英]Pytest Unit Testing Sending Email SMTP

I want to test the following function in pytest without actually creating an SMTP server and sending email to the specified address.我想在 pytest 中测试以下 function 而不实际创建 SMTP 服务器并将 Z0C83ZEFAB23 发送到指定的地址。

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

I am aware that SMTP server can be mocked using the python unittest module as per https://jingwen-z.github.io/how-to-send-emails-with-python/ but I cannot figure it out using pytest. I am aware that SMTP server can be mocked using the python unittest module as per https://jingwen-z.github.io/how-to-send-emails-with-python/ but I cannot figure it out using pytest. I would like to be able to do this in pytest if possible given all my other tests use the module.如果可能的话,我希望能够在 pytest 中执行此操作,因为我的所有其他测试都使用该模块。

I'm not entirely sure what you are looking for, as your function doesn't return anything.我不完全确定您在寻找什么,因为您的 function 没有返回任何内容。 But i guess you can assert which functions are called inside send_email_investor_owner_occupier .但我想你可以断言在send_email_investor_owner_occupier中调用了哪些函数。

To use mocker in pytest, what i do is install the pytest-mock module.要在 pytest 中使用 mocker,我要做的是安装pytest-mock模块。 You can then define you test as:然后,您可以将测试定义为:

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

If you know how to mock in unittest, then mocking in pytest is pretty easy.如果你知道如何在 unittest 中模拟,那么 pytest 中的 mocking 就很容易了。

Say that your python module that contains the send_email_investor_owner_occupier method is called my_email_sender.py , then you patch my_email_sender.smtplib.SMTP .假设包含send_email_investor_owner_occupier方法的 python 模块称为my_email_sender.py ,然后修补my_email_sender.smtplib.SMTP

One way of doing it would be using the patch decorator:一种方法是使用补丁装饰器:

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

Another way would be to use the pytest-mock plugin to pytest:另一种方法是对 pytest 使用pytest-mock插件:

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

This might seem a bit tedious, but if you have several tests which check the mail sending and you want to mock all of them easily without copying the same code you can mix this approach with a pytest fixture :这可能看起来有点乏味,但是如果您有几个检查邮件发送的测试,并且您想轻松地模拟所有这些测试而不复制相同的代码,您可以将此方法与pytest 夹具混合使用:

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

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

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