如何测试登录过程?

Posted

技术标签:

【中文标题】如何测试登录过程?【英文标题】:How to test login process? 【发布时间】:2014-04-22 20:19:09 【问题描述】:

我正在使用 Django 1.6 开发一个 Web 应用程序,我要求用户使用我的登录表单登录。我想写一个测试用户登录过程的测试用例。

我确实成功地获得了一个有效的登录页面,这意味着我能够登录。以下步骤解释了我的设置。然而,为此过程编写测试用例确实失败了。在这一点上,我既不能在我的测试中发现错误,也不能确定这种方法是否有意义。有人可以帮我吗?

更新:与此同时,我注意到我的表单错误消息太不具体了。该问题似乎是由未通过某些表单验证步骤的空表单字段引起的。当我将错误 form.errors 添加到模板中时,响应包含以下内容(格式不太好):

<ul class="errorlist">
  <li>username
    <ul class="errorlist">
      <li>This field is required.</li>
    </ul>
  </li>
  <li>password
    <ul class="errorlist">
      <li>This field is required.</li>
    </ul>
  </li>
</ul>

我仍然不确定如何最合理地测试此过程。我对 Django 和它的测试框架的理念很陌生。可能这个问题不直接属于 Django 测试框架的范围,其中模型、视图和表单(似乎)旨在进行测试,而不是彼此分离?此测试是否属于进行黑盒/功能测试(例如,使用 Selenium)的独立测试套件的领域?


我是这样开始的:

    开始一个新项目,像这样:

    django-admin.py startproject login_test
    

    login_test/urls.py 中添加了一个条目,如下所示:

    urlpatterns = patterns('',
        url(r'^login/$', 'django.contrib.auth.views.login'),
        url(r'^admin/', include(admin.site.urls)),
    )
    

    /home/moooeeeep/login_test/templates/registration/login.html 制作了一个模板,如下所示:

    % if form.errors %
    <p>Your username and password didn't match. Please try again.</p>
    % endif %
    % if not user.is_active %
    <form method="post" action="% url 'django.contrib.auth.views.login' %">
      % csrf_token %
       form.as_p 
      <button type="submit">Login</button>
      <input type="hidden" name="next" value="% url 'django.contrib.auth.views.login' %" />
    </form>
    % else %
    <p>You are logged in as <strong> user.username </strong>.</p>
    % endif %
    

    将模板目录添加到login_test/settings.py中的TEMPLATE_DIRS,像这样:

    TEMPLATE_DIRS = (
        '/home/moooeeeep/login_test/templates/',
    )
    

    同步数据库以获取与身份验证相关的表,并添加一个超级用户,如下所示:

    python manage.py syncdb
    

如果我没有错过任何一步,此时我可以登录我的网站。登录时,我会显示我的用户名,如果没有,我会看到表单,如果登录失败,还会显示一条错误消息。


然而,我的测试用例,在提交正确的帖子数据后,会看到登录失败的响应,用户没有登录。

这是我的login_test/tests.py

from django.contrib.auth.models import User
from django.contrib.auth import SESSION_KEY
from django.test import TestCase

class LogInTest(TestCase):
    def setUp(self):
        self.credentials = 
            'username': 'testuser',
            'password': 'secret'
        User.objects.create_user(**self.credentials)
    def test_login(self):
        # login
        response = self.client.post('/login/', **self.credentials)      
        # should be logged in now, fails however
        self.assertTrue(response.context['user'].is_active)

这是输出:

$ python manage.py test
Creating test database for alias 'default'...
F
======================================================================
FAIL: test_login (login_test.tests.LogInTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/moooeeeep/login_test/login_test/tests.py", line 16, in test_login
    self.assertTrue(response.context['user'].is_active)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 1 test in 0.008s

FAILED (failures=1)
Destroying test database for alias 'default'...

这是我的login_test/settings.py

import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '+6e-6t8dnl$75fx%=7y$+4ipo&i=kvw(p*963p37)7o$1-)30u'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)
MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'login_test.urls'
WSGI_APPLICATION = 'login_test.wsgi.application'
DATABASES = 
    'default': 
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    

TEMPLATE_DIRS = (
    '/home/moooeeeep/login_test/templates/',
)

【问题讨论】:

您能检查一下response.context['user'] 中的内容吗? @alecxe 这是AnonymousUser。 好的,请显示你的设置,尤其是我关心AUTHENTICATION_BACKENDS设置。 @alecxe 请看我的编辑。显然这是一个表单验证问题。错误消息抱怨空表单字段。 我不确定为什么你认为表单是罪魁祸首,login 视图在测试期间被调用。您能否显示您的设置(请同时包括您的中间件)?谢谢。 【参考方案1】:

你不想检查“is_active”布尔值,你想检查

response.context['user'].is_authenticated

见: https://docs.djangoproject.com/en/dev/topics/auth/default/#authentication-in-web-requests

和: https://docs.djangoproject.com/en/dev/ref/contrib/auth/

【讨论】:

无济于事,因为request.context 中有一个AnonymousUser 在这种情况下不会有帮助,但是一旦您解决了 AnonymouseUser 问题(即用户未登录),那么您仍然需要检查 is_authenticated 而不是 is_active 您可以尝试使用 self.client.login(username="", password="") 以确保用户能够登录。 两个链接都没有找到! @Mahdimehrabi 没有找到这些链接我并不感到惊讶,这个答案已有 7 年历史,适用于非常旧的 Django 版本【参考方案2】:

我发现我传递的post参数是错误的(字典一定不能解包)。我还需要了解,我需要在发送数据后遵循 post 请求发出的重定向。然后我的登录测试成功了(尽管重定向目标的页面还不存在)。

这是我更新的测试用例:

from django.contrib.auth.models import User
from django.test import TestCase

class LogInTest(TestCase):
    def setUp(self):
        self.credentials = 
            'username': 'testuser',
            'password': 'secret'
        User.objects.create_user(**self.credentials)
    def test_login(self):
        # send login data
        response = self.client.post('/login/', self.credentials, follow=True)
        # should be logged in now
        self.assertTrue(response.context['user'].is_active)

这是输出:

$ python manage.py test
Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.196s

OK
Destroying test database for alias 'default'...

【讨论】:

以上是关于如何测试登录过程?的主要内容,如果未能解决你的问题,请参考以下文章

某系统单点登录性能测试诊断分析优化过程

某系统单点登录性能测试诊断分析优化过程分享

如何在登录过程中生成rest_framework_jwt token

面试题:登录功能如何测试?

测试过程中bug分类

性能测试:Jmeter压测过程中的短信验证码读取