繁体   English   中英

Django单元测试(带有DRF):如何测试Passwordresetview?

[英]Django Unit Testing (with DRF): How to test a Passwordresetview?

我目前正在尝试编写单元测试以成功重置密码。

TLDR:我无法弄清楚如何在设置密码视图的发布请求中处理表单数据的注入。

对于上下文,让我先给您我的代码,因为一行代码说出1000多个单词。

账户/ API / views.py:

class PasswordResetView(generics.GenericAPIView):
    """(POST) Expects email. Sends a password reset mail to email."""
    permission_classes = (permissions.AllowAny,)
    serializer_class = PasswordResetSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            user = User.objects.get(email=serializer.data['email'])
            if user.is_active and user.has_usable_password():
                send_password_reset_email(user, request)
                return Response(
                    {"detail": "A password reset email has been send."},
                    status=status.HTTP_204_NO_CONTENT
                )
            else:
                return Response(
                    {"detail": "This users password can't be reset."},
                    status=status.HTTP_406_NOT_ACCEPTABLE
                )

账户/ API / urls.py:

url(r'^password_reset/$', views.PasswordResetView.as_view(),
    name="password_reset"),

账户/ API / serializers.py:

class PasswordResetSerializer(serializers.Serializer):
    email = serializers.EmailField()

    def validate_email(self, value):
        if User.objects.filter(email__iexact=value).exists():
            return value
        else:
            raise serializers.ValidationError("Email not found.")

账户/ utils.py:

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.contrib.sites.shortcuts import get_current_site
from django.utils import six
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode

from templated_email import send_templated_mail

password_reset_token = PasswordResetTokenGenerator()


def build_email_context(user_obj, request):
    current_site = get_current_site(request)
    context = {
        "name": "",
        "domain": current_site.domain,
        "uid": urlsafe_base64_encode(force_bytes(user_obj.pk)),
        'token': password_reset_token.make_token(user_obj)
    }
    if user_obj.name != "":
        context["name"]: " " + user_obj.name
    return context


def send_password_reset_email(user_obj, request):
    context = build_email_context(user_obj, request)
    send_templated_mail(
        template_name="password_reset",
        from_email="noreply@ordersome.com",
        recipient_list=[user_obj.email],
        context=context
    )

链接到电子邮件中的路由的视图是django.contrib.auth中的标准CBV PasswordResetConfirmView和PasswordResetDoneView。

这是我为此密码重置序列编写的测试:

API /测试/ test_views.py:

from django.contrib.auth import get_user, get_user_model
from django.core import mail
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.reverse import reverse as api_reverse
from rest_framework.test import APITestCase

User = get_user_model()


class UserAPIViewsTestCase(APITestCase):
    def setUp(self):
        User.objects.create_user(
            email="testuser@test.com", password="test1234")
        self.login_url = api_reverse("api:auth:login")
        self.register_url = api_reverse("api:auth:register")
        self.password_reset_url = api_reverse("api:auth:password_reset")
        self.password_change_url = api_reverse("api:auth:password_change")
        self.user_delete_url = api_reverse("api:auth:user_delete")

    def test_api_auth_password_reset_success(self):
        """Test if a password reset successfully resets password."""
        pre_user = User.objects.get(email="testuser@test.com")
        self.assertEqual(pre_user.check_password("test1234"), True)
        email_data = {
            "email": "testuser@test.com",
        }
        email_response = self.client.post(
            self.password_reset_url, email_data, format="json")
        self.assertEqual(email_response.status_code,
                         status.HTTP_204_NO_CONTENT)
        password_reset_data = {
            "new_password1": "newtest1234",
            "new_password2": "newtest1234"
        }
        password_reset_response = self.client.get(
            mail.outbox[0].body[-94:-37], format="json", follow=True)
        path = password_reset_response.request["PATH_INFO"]
        done_url = "http://testserver" + path
        password_reset_done_response = self.client.post(
            done_url, password_reset_data, format="json")
        post_user = User.objects.get(email="testuser@test.com")
        self.assertEqual(post_user.check_password("newtest1234"), True)

最后一个self.assertEqual失败。 但是,当我手动测试视图时,它可以工作,因此代码应该正确。 我应该如何修改测试?

当我注销done_url它会给我http://testserver/auth/reset/MQ/set-password/ ,这应该是正确的路径。

当我注销password_reset_done_response它说,这是TemplateResponse,status_code是200(这应该表示成功,但不是)。 同样,此响应似乎仍具有路径/auth/reset/MQ/set-password/ ,现在不再是这种情况了。

password_reset_data不完整-没有信息将新密码应用于哪个用户。

from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode

...

password_reset_data = {
    'uid': urlsafe_base64_encode(force_bytes(pre_user.pk)),
    'token': default_token_generator.make_token(pre_user),
    'new_password1': 'newtest1234',
    'new_password2': 'newtest1234',
}

其他建议

  • setUp(self)应该调用super().setUp()
  • 使用self.assertTrue而不是self.assertEqual
  • post_user ,在最后声明之前使用pre_user.refresh_from_db()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM