Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何为django表单视图编写测试?_Python_Django_Django Forms - Fatal编程技术网

Python 如何为django表单视图编写测试?

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

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