Python 如何为django表单视图编写测试?
Django v1.10 FormView代码:Python 如何为django表单视图编写测试?,python,django,django-forms,Python,Django,Django Forms,Django v1.10 FormView代码: class PasswordResetConfirmView(FormView): template_name = "dashboard/account/reset_password_form.html" success_url = '/dashboard/' form_class = SetPasswordForm def authenticate_password_token(self, request, u
class PasswordResetConfirmView(FormView):
template_name = "dashboard/account/reset_password_form.html"
success_url = '/dashboard/'
form_class = SetPasswordForm
def authenticate_password_token(self, request, uidb64=None, token=None, encodedtimestring=None):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
timestring = force_text(urlsafe_base64_decode(encodedtimestring))
timestamp = timeparse(timestring)
timediff = timezone.now() - timestamp
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
timediff = None
if timediff is None or timediff.days < 0 or timediff.days > PASSWORD_RESET_TIMEOUT_DAYS:
messages.error(request, _(
'The reset password link is no longer valid.'))
return None
if user is None or not default_token_generator.check_token(user, token):
messages.error(request, _('The reset password link is not valid.'))
return None
return user
def get(self, request, uidb64=None, token=None, encodedtimestring=None, *arg, **kwargs):
form = self.form_class()
assert uidb64 is not None and token is not None and encodedtimestring is not None
user = self.authenticate_password_token(
request, uidb64, token, encodedtimestring)
if user is None:
return redirect(reverse('dashboard-login'))
return self.render_to_response(self.get_context_data(form=form))
def post(self, request, uidb64=None, token=None, encodedtimestring=None, *arg, **kwargs):
form = self.form_class(request.POST)
assert uidb64 is not None and token is not None and encodedtimestring is not None
user = self.authenticate_password_token(
request, uidb64, token, encodedtimestring)
if user is None:
return redirect(reverse('dashboard-login'))
if not form.is_valid():
return self.form_invalid(form)
new_password = form.cleaned_data['new_password2']
try:
with transaction.atomic():
user.auth_token.delete()
Token.objects.create(user=user)
user.set_password(new_password)
user.save()
except:
messages.error(request, _('Password reset was unsuccessful.'))
return redirect(reverse('dashboard-login'))
messages.success(request, _('Password has been reset.'))
return redirect(reverse('dashboard-login'))
我尝试编写测试用例:
class ResetPasswordEmailTest(BaseApiTest):
def test_password_reset_form(self):
"""
Ensure that the authenticate token works
"""
self.client.logout()
token = default_token_generator.make_token(self.user)
uidb64 = force_bytes(self.user.id)
timenow = force_bytes(timezone.now())
response = self.client.get(
reverse('reset-password-confirm',
args=[urlsafe_base64_encode(uidb64), token,
urlsafe_base64_encode(timenow)]))
self.assertEqual(response.status_code, status.HTTP_200_OK)
我收到的错误消息:
tests/password_tests.py", line 129, in test_password_reset_form
self.assertEqual(response.status_code, status.HTTP_200_OK)
AssertionError: 302 != 200
我不知道如何编写一个测试类来测试formview的所有3个方法。我的尝试只是测试get
方法
更新:
失败的真正原因与用户登录无关,但不知何故,PasswordTokenGenerator
固有的check\u-token
方法使我的测试失败
随着我做更多的研究,我认为最好将Django v1.10升级到v1.11,在那里我需要重写整个内容,这可能会使这个问题的必要性失效。你的get方法PasswordResetConfirmView
有两种不同的响应
重定向
当用户为None时,它将使用重定向URI进行响应
if user is None:
return redirect(reverse('dashboard-login'))
因此,在这种情况下,响应的状态代码将是means
您被重定向到其他URL
根据响应进行渲染
当存在用户时,响应返回的信息就是请求中使用的方法
return self.render_to_response(self.get_context_data(form=form))
因此,在这种情况下,响应的状态代码将是表示
请求已成功
解决方案: 为了使您的测试用例通过,您可以使用 如果您的请求使用了follow参数,则预期的\u url和目标\u状态\u代码将是重定向链最后一点的url和状态代码 参考: 或者,您可以创建两个单独的测试用例(当用户登录时,当用户未登录时),并使用assertEqual
# Test for logged in user.
def test_password_reset_form_for_logged_in_user(self):
...
# do stuff
self.assertEqual(response.status_code, status.HTTP_200_OK)
# Test if user not logged in.
def test_password_reset_form_if_user_not_logged_in(self):
...
# do stuff
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
问题(验尸):
让我们从定义问题开始:
- 状态302: 请求的资源临时驻留在不同的URI下- 因此,我们假设您正在被重定向,因此测试失败
- 发生这种情况的地方:
在您的
方法中,我们可以找到以下代码:get()
因此,如果用户是if user is None: return redirect(reverse('dashboard-login'))
(未经验证),视图会将其重定向到登录页面匿名的
PasswordResetConfirmView.get()
发出未经验证的请求时,就会出现问题
解决方案: 在发出请求之前,您需要验证(登录)您的用户。
您可以使用以下方法进行此操作: 如果您的站点使用Django的身份验证系统,则可以使用
force\u login()
方法模拟用户登录站点的效果。当测试要求用户登录且用户登录方式的详细信息不重要时,请使用此方法,而不是login()
嘿,@KimStacks我在想,这些答案对你有帮助吗?嗨@JohnMoutafis很抱歉一直忙于其他任务,所以没有时间测试答案。“将在周末完成。@JohnMoutafis失败的真正原因与用户登录无关,但PasswordTokenGenerator中固有的check_token方法在某种程度上使我的测试失败。随着我做更多的研究,我认为最好将Django v1.10升级到v1.11,在那里我需要重写这整件事,这可能会使对这个问题的需要失效。你所说的
check\u token
方法失败是什么意思?KimStacks的错误是什么?
def test_password_reset_form(self):
...
# A URL that redirects can be followed to termination.
response = self.client.get(reverse('reset-password-confirm', args=[...]), follow=True)
self.assertRedirects(response, reverse('dashboard-login'), status_code=302, target_status_code=200)
self.assertEqual(len(response.redirect_chain), 2)
# Test for logged in user.
def test_password_reset_form_for_logged_in_user(self):
...
# do stuff
self.assertEqual(response.status_code, status.HTTP_200_OK)
# Test if user not logged in.
def test_password_reset_form_if_user_not_logged_in(self):
...
# do stuff
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
if user is None:
return redirect(reverse('dashboard-login'))
def my_test_case():
... Do stuff ...
# Login
self.client.force_login(self.user)
# Make the request
response = self.client.get(...)