Тестирование Django 1-5 Reset Password Form - как сгенерировать токен для теста?
В следующем тесте токен не распознается как действительный. В моем ручном тесте он работает, так что я что-то упускаю в способе генерации пароля.
def test_actual_reset_password(self):
new_password = "myNewPassword012*"
token_generator = PasswordResetTokenGenerator()
user = UserFactory.create()
token = token_generator.make_token(user=user)
response = self.assert_page_loading(path="/forgot-password/reset/{0}/".format(token))
print response
# That loads the page with the error message mentioning that the token was already used
# So I cannot carry on:
form = response.form
form['new_password1'] = new_password
form['new_password2'] = new_password
response = form.submit()
В исходном коде django, в PasswordResetForm я нашел этот код; Я не вижу, в чем разница:
def save(self, ..., token_generator=default_token_generator, ...):
"""
Generates a one-use only link for resetting password and sends to the
user.
"""
...
for user in self.users_cache:
...
c = {
...
'token': token_generator.make_token(user),
...
}
...
send_mail(subject, email, from_email, [user.email])
3 ответа
Хорошо, я просто искал информацию о том, как это сделать, и ваш вопрос побудил меня сам разобраться. Я не уверен, что вы все еще работаете над этим, но вот как я заставил это работать:
from django.core import mail
# First we get the initial password reset form.
# This is not strictly necessary, but I included it for completeness
response = self.c.get(reverse('password_reset'))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.template_name, 'authentication/password_reset_form.html')
# Then we post the response with our "email address"
response = self.c.post(reverse('password_reset'),{'email':'fred@home.com'})
self.assertEqual(response.status_code, 302)
# At this point the system will "send" us an email. We can "check" it thusly:
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Password reset on example.com')
# Now, here's the kicker: we get the token and userid from the response
token = response.context[0]['token']
uid = response.context[0]['uid']
# Now we can use the token to get the password change form
response = self.c.get(reverse('password_reset_confirm', kwargs={'token':token,'uidb64':uid}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.template_name, 'authentication/password_reset_confirm.html')
# Now we post to the same url with our new password:
response = self.c.post(reverse('password_reset_confirm',
kwargs={'token':token,'uidb36':uid}), {'new_password1':'pass','new_password2':'pass'})
self.assertEqual(response.status_code, 302)
И это все! Не так сложно в конце концов.
Вот как я это сделал для функционального теста:
def test_password_reset_from_key(self):
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import base36_to_int, int_to_base36
user = User.objects.all()[:1].get()
token = default_token_generator.make_token(user)
self.get("/accounts/password/reset/key/%s-%s/" % (int_to_base36(user.id), token))
self.selenium.find_element_by_name("password1").send_keys("password")
self.selenium.find_element_by_name("password2").send_keys("password")
self.selenium.find_element_by_name("action").submit()
alert = self.selenium.find_element_by_css_selector(".alert-success")
self.assertIn('Password successfully changed.', alert.text)
Это работает для Django 4.1:
def test_can_reset_password(self) -> None:
user = UserMother.random()
uid = urlsafe_base64_encode(force_bytes(user.pk))
token = default_token_generator.make_token(user)
url = self._get_url(uid, token)
redirect_response = self.client.get(url)
redirected_url = self._get_url(uid, "set-password")
self.assertRedirects(
redirect_response, redirected_url, fetch_redirect_response=True
)
form = {"new_password1": "NEW_PASSWORD", "new_password2": "NEW_PASSWORD"}
response = self.client.post(redirected_url, form)
self.assertRedirects(response, self.URL_COMPLETE, fetch_redirect_response=False)
updated_user = User.objects.get(id=user.id)
self.assertTrue(updated_user.check_password(form["new_password1"]))
Соответствующий импорт:
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode