0

I'm trying to test a Django model form that overrides the save method and implements a custom send_mail function. The send_mail function uses loader.render_to_string to generate an email body and then calls a custom send_email function to send the email. I'm having trouble writing the test case to properly assert the usage of these functions.

Here's my code:

class MockObjects:
    def mock_render_to_string(self):
        return 'This is an email'


class FormsTestCase(TestCase):
    mock = MockObjects()

    @patch('django.template.loader.render_to_string')
    @patch('ext_libs.sendgrid.sengrid.send_email')
    def test_send_mail(self, mock_send_email, mock_render_to_string):
        form = CustomPasswordResetForm()
        context = {'site_name': 'YourSiteName'}
        to_email = 'testuser@example.com'

        mock_render_to_string.return_value = self.mock.mock_render_to_string()
        mock_send_email.return_value = None

        form.send_mail(context, to_email)

        mock_render_to_string.assert_called_once_with('registration/password_reset_email.html', context)

        mock_send_email.assert_called_once_with(
            destination=to_email,
            subject="Password reset on YourSiteName",
            content=mock_render_to_string.return_value
        )


class CustomPasswordResetForm(PasswordResetForm):
    def send_mail(self, context, to_email, *args, **kwargs):
        print('got here')
        email_template_name = 'registration/password_reset_email.html'
        print('should call them')
        body = loader.render_to_string(email_template_name, context)
        print(f'got body {body}')
        print('sending mail')
        send_email(destination=to_email, subject=f"Password reset on {context['site_name']}", content=body)
        print('sent')

#ext_libs.sendgrid.sengrid.send_email
def send_email(destination, subject, content, source=None, plain=False):
    print('did it get here')
    print(f'{destination}, {subject} {content}')

The issue I'm facing is that the test is failing with the following error:

AssertionError: Expected 'mock' to be called once. Called 0 times.

I traced the execution and the mocked classes are being called. Here is the full logs with prints

python .\manage.py test user.tests.test_forms.FormsTestCase.test_send_mail
{'default': {'ENGINE': 'django.db.backends.postgresql', 'NAME': 'feed_replica', 'USER': 'postgres', 'PASSWORD': 'P0stgres1.', 'HOST': 'localhost', 'PORT': '5432'}}
Creating test database for alias 'default'...
System check identified no issues (0 silenced).

Running tests...
----------------------------------------------------------------------
got here
should call them
got body This is an email
sending mail
did it get here
testuser@example.com, Password reset on YourSiteName This is an email
end of method
sent
F
FAIL [5.601s]: test_send_mail (user.tests.test_forms.FormsTestCase.test_send_mail)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Local\Programs\Python\Python311\Lib\unittest\mock.py", line 1369, in patched
    return func(*newargs, **newkeywargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test_forms.py", line 103, in test_send_mail
    mock_send_email.assert_called()
  File "Local\Programs\Python\Python311\Lib\unittest\mock.py", line 902, in assert_called
    raise AssertionError(msg)
AssertionError: Expected 'send_email' to have been called.

Can anyone please show me why this issue is ocurring?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Femolak
  • 31
  • 4

0 Answers0