Reputation: 8744
I am trying to use Mock with Django for two things: 1. Get a user (we have a custom backend that makes network calls that I want to avoid) 2. Mock out another method that gets a token for password resets over the network.
Here is the test:
@patch('core.views.KagisoUser')
def test_forgot_password_sends_reset_email(self, MockKagisoUser): # noqa
email = '[email protected]'
user = MagicMock()
user.email = email
user.generate_reset_password_token.return_value = email
MockKagisoUser.objects.first.return_value = user
data = {'email': email}
client = Client()
response = client.post('/forgot_password/', data, follow=True)
message = list(response.context['messages'])[0].message
assert response.status_code == 200
assert 'You will receive an email with reset instructions shortly' \
== message
assert len(mail.outbox) == 1
assert mail.outbox[0].to[0] == email
assert mail.outbox[0].subject == 'Password Reset'
assert mail.outbox[0].alternatives[0] # HTML body
I get this error:
self = <django.core.mail.message.EmailMultiAlternatives object at 0x7f52eacd3390>
def message(self):
encoding = self.encoding or settings.DEFAULT_CHARSET
msg = SafeMIMEText(self.body, self.content_subtype, encoding)
msg = self._create_message(msg)
msg['Subject'] = self.subject
msg['From'] = self.extra_headers.get('From', self.from_email)
> msg['To'] = self.extra_headers.get('To', ', '.join(self.to))
E TypeError: sequence item 0: expected str instance, MagicMock found
Here is the implementation:
def forgot_password(request):
reset_message = 'You will receive an email with reset instructions shortly'
not_found_message = 'We could not find a user for that email address'
if request.method == 'POST':
form = forms.ForgotPasswordForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
user = KagisoUser.objects.filter(email=email).first()
if user:
print(user.email)
token = user.generate_reset_password_token()
url = request.build_absolute_uri(reverse('reset_password'))
message = render_to_string(
'core/emails/reset_password.html',
{
'url': url,
'token': token,
'user_id': user.id
}
)
send_mail(
'Password Reset',
'',
'[email protected]',
[user.email],
html_message=message
)
messages.success(request, reset_message)
return HttpResponseRedirect('/')
else:
messages.error(request, not_found_message)
return HttpResponseRedirect(reverse('forgot_password'))
else:
form = forms.ForgotPasswordForm()
return render(
request,
'core/auth/forgot_password.html',
{'form': form}
)
What am I doing wrong?
Upvotes: 0
Views: 4346
Reputation: 2095
stack trace would be really useful...
but besides that it seems you mocker out MockKagisoUser.objects.first
whereas your view gets the user from KagisoUser.objects.filter(email=email).first()
so you're missing filter
mock_filter = MagicMock()
mock_filter.first.return_value = user
MockKagisoUser.objects.filter.return_value = mock_filter
the above should return you a filter that will return your user when getting first
which in turn will return your user in your view rather than returning MagicMock instance
Upvotes: 1