简体   繁体   English

Django中的单元测试看不到成功登录的正确重定向URL?

[英]Unit test in Django dont see correct redirect url for successfull login?

In my Django project I create custom admin page (NOT admin from Django). 在我的Django项目中,我创建了自定义管理页面(不是Django的管理员)。 I have 2 login pages. 我有2个登录页面。 One for admin, second for other users. 一个用于管理员,第二个用于其他用户。

Here below you can see urls.py file for admin. 在下面,您可以看到admins的urls.py文件。 I test it and it works fine. 我对其进行了测试,并且效果很好。 After successful login Django redirect user to url which was next parameter ( /administration/dashboard/ ). 成功登录后,Django将用户重定向到下一个参数url( /administration/dashboard/ )。

I wrote unit test and it raise error. 我写了单元测试 ,它引发了错误。 From error I understand that Django redirect to default url ( /accounts/profile/ ). 从错误中我了解到Django重定向到默认URL( /accounts/profile/ )。 Why unit test dont use settings which I did in urls.py file (next parameter)? 为什么单元测试不使用我在urls.py文件(下一个参数)中所做的设置?

How to fix this problem? 如何解决这个问题?

Right now I notice that problem disappear only if I use this code LOGIN_REDIRECT_URL = '/administration/dashboard/' in settings.py . 现在,我注意到只有在settings.py中使用此代码LOGIN_REDIRECT_URL = '/administration/dashboard/' ,该问题才会消失。 I cant use it cause in the future I will use LOGIN_REDIRECT_URL to my other login page. 我无法使用它,因为将来我将使用LOGIN_REDIRECT_URL进入其他登录页面。

I would be grateful for any help! 我将不胜感激!

urls.py: urls.py:

from django.contrib.auth import views as authentication_views

urlpatterns = [
    # Administration Login
    url(r'^login/$',
        authentication_views.login,
        {
            'template_name': 'administration/login.html',
            'authentication_form': AdministrationAuthenticationForm,
            'extra_context': {
                'next': reverse_lazy('administration:dashboard'),
            },
            'redirect_authenticated_user': True
        },
        name='administration_login'),
]

tests.py: tests.py:

class AdministrationViewTestCase(TestCase):
    def setUp(self):
        self.client = Client()
        self.credentials = {'username': 'user', 'password': 'password'}
        self.user = User.objects.create_user(self.credentials, is_staff=True)
        self.data = dict(
            self.credentials,
            next=reverse("administration:dashboard")
        )

    def test_administration_authorization(self):
        self.assertTrue(self.user)

        # logged_in = self.client.login(**self.credentials)
        # self.assertTrue(logged_in)

        response = self.client.post(
            reverse("administration:administration_login"),
            self.data,
            follow=True
        )
        # self.assertEqual(response.status_code, 302)
        self.assertRedirects(
            response,
            reverse("administration:dashboard"),
            status_code=302,
            target_status_code=200
        )

ERROR: 错误:

Traceback (most recent call last):
  File "/home/nurzhan/CA/administration/tests.py", line 51, in test_administration_authorization
    reverse("administration:dashboard"),
  File "/srv/envs/py27/lib/python2.7/site-packages/django/test/testcases.py", line 271, in assertRedirects
    % (response.status_code, status_code)
AssertionError: Response didn't redirect as expected: Response code was 200 (expected 302)

forms.py: forms.py:

from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import ugettext_lazy as _


class AdministrationAuthenticationForm(AuthenticationForm):
    """
        A custom authentication form used in the administration application.
    """
    error_messages = {
        'invalid_login': (
            _("ERROR MESSAGE.")
        ),
    }
    required_css_class = 'required'

def confirm_login_allowed(self, user):
    if not user.is_active or not user.is_staff:
        raise forms.ValidationError(
            self.error_messages['invalid_login'],
            code='invalid_login',
            params={
                'username': self.username_field.verbose_name
            }
        )

login.html: login.html:

<form action="{% url 'administration:administration_login' %}" method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <input type="submit" value="Submit">
  <input type="hidden" name="next" value="{{ next }}"/>
</form>

Django isn't checking next in extra_context but in GET and POST params. Django不会在extra_context检查next而是在GETPOST参数中进行检查。

extra_context is used to update your template context . extra_context用于更新模板上下文 So if you want to pass the values for variables to your template you can set those with extra_context . 因此,如果要将变量的值传递到模板,则可以使用extra_context进行设置。

However, you can fix your test by either setting LOGIN_REDIRECT_URL in settings.py or passing next as a POST or GET param. 但是,您可以通过settings.py设置LOGIN_REDIRECT_URL或将其作为POST或GET参数作为下一个参数来修复测试。

params = dict(**self.credentials, next=reverse("home:index"))
response = self.client.post(
    url,
    params,
    follow=True
)

NOTE: 注意:

self.credentials should be unpacked in the dict being applied to self.data . self.credentials应该在应用于self.data的字典中解压缩。

self.data = dict(
    **self.credentials,
    next=reverse("administration:dashboard")
)

If you wanted to test without making this change, I can recommend another way to test this. 如果您想在不做任何更改的情况下进行测试,我可以建议另一种测试方法。

You need to render your template in a browser and fill out the login form. 您需要在浏览器中呈现模板并填写登录表单。 This way your browser client will make the POST request with next passed as a parameter. 这样,您的浏览器客户端将发出POST请求,并将next作为参数传递。 You can get this done with a headless browser using selenium webdriver . 您可以使用selenium webdriver在无头浏览器中完成此操作。

Have you tried removing the follow=True in the POST request. 您是否尝试过在POST请求中删除follow=True You are checking for a redirection but you are telling the requests modules to follow the redirection, so your response will be directly the page and not the 302 redirection HTTP response. 您正在检查重定向,但是您告诉requests模块遵循重定向,因此您的响应将直接是页面,而不是302重定向HTTP响应。

To be more explicit. 更明确地说。 You are sending a request with requests.post(follow=True) , that will follow the 302 redirection to the destination page and your response will be a HTTP 200 with the destination page. 您正在发送带有requests.post(follow=True)的请求,该requests.post(follow=True)将遵循302重定向到目标页面,并且您的response将是带有目标页面的HTTP 200。 Even if the destination page is the one you want, the test assertion will fail because is looking for a HTTP 302 code in your response and you've already followed the redirection. 即使目标页面是您想要的页面,测试断言也会失败,因为正在响应中寻找HTTP 302代码并且您已经遵循了重定向。

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

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