【问题标题】:How to Create Session Variables in Selenium/Django Unit Test?如何在 Selenium/Django 单元测试中创建会话变量?
【发布时间】:2012-12-28 13:21:00
【问题描述】:

我正在尝试编写一个使用 Selenium 来测试 Django 视图的功能测试。当用户来到一个页面(“page2”)时,呈现该页面的视图期望找到一个会话变量“uid”(用户 ID)。我已经阅读了六篇关于如何做到这一点的文章,但没有一篇对我有用。下面的代码显示了 Django documentation 说它应该如何完成,但它对我也不起作用。当我运行测试时,视图永远不会完成执行,并且我收到“发生服务器错误”消息。有人可以告诉我我做错了什么吗?谢谢。

views.py:

from django.shortcuts import render_to_response

def page2(request):
    uid = request.session['uid']
    return render_to_response('session_tests/page2.html', {'uid': uid})

test.py:

from django.test import LiveServerTestCase
from selenium import webdriver
from django.test.client import Client

class SessionTest(LiveServerTestCase):

    def setUp(self):
        self.browser = webdriver.Firefox()
        self.browser.implicitly_wait(3)
        self.client = Client()
        self.session = self.client.session
        self.session['uid'] = 1

    def tearDown(self):
        self.browser.implicitly_wait(3)
        self.browser.quit()

    def test_session(self):
        self.browser.get(self.live_server_url + '/session_tests/page2/')
        body = self.browser.find_element_by_tag_name('body')
        self.assertIn('Page 2', body.text)

【问题讨论】:

  • 我看不到您在会话中设置 uid 的位置,它应该类似于 request.session['uid'] = uid。从 session 中恢复 uid 的方式是可以的,所以如果你在 session 上设置 uid 是正确的,那么这不是 session 变量的问题。
  • (我认为)我正在将 uid 添加到我的会话状态中,上面的 setUp 函数的最后一行:self.session['uid'] = 1。
  • 嗯,有一个简单的方法来测试它。在您看来,尝试从会话中获取 uid,如下所示:uid = request.session.get('uid', None),然后打印或记录 uid 变量并查看 uid 是否为 None,这是 case key 'uid' 的默认值在会话中找不到。
  • 经过大量在线研究,我发现了如何做到这一点。但是,它确实要求您使用 Django 的 TestCase 类而不是 Selenium 的 webdriver 类。我怀疑 webdriver 的浏览器对象和 Django 允许您创建的会话状态之间存在脱节。如果确实如此,它会对我的测试产生负面影响,因为这意味着我不能使用 Selenium 来测试任何假设初始会话状态的页面。因此,我仍然希望找到一些解决方案。
  • @Robert 在类似情况下(非 Django) 我已经为测试框架设置了特殊的 URL,以便将内容插入会话。不愉快,但确实有效。或者,您可以通过 selenium 驱动程序找出会话 ID(一旦打开第一页),然后在测试代码中查找(并更改)该会话。

标签: django django-views selenium-webdriver


【解决方案1】:

在 Django 的 bug tracker 中有几张关于这类问题的票,主要的一张似乎是:https://code.djangoproject.com/ticket/10899 几个月没有任何动静。基本上,您需要做一些额外的设置才能使会话正常工作。以下是对我有用的方法(可能不适用于您的特定设置,因为我没有使用 Selenium):

def setUp(self):
    from django.conf import settings
    engine = import_module(settings.SESSION_ENGINE)
    store = engine.SessionStore()
    store.save()
    self.client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key

现在您应该可以访问self.client.session,它应该会记住您对其所做的任何更改。

【讨论】:

  • 谢谢,但我知道该怎么做。我的问题特别询问了如何使用 Selenium 来做这件事,因为它是一个很好的功能测试工具,这似乎是一种很常见的情况,期望在进入页面时设置会话变量。不过,我非常感谢您抽出时间来回答。
【解决方案2】:

以下是解决此问题的方法。 James Aylett 在上面提到会话 ID 时暗示了解决方案。 jscn 展示了如何设置会话,但他没有提到会话密钥对解决方案的重要性,也没有讨论如何将会话状态链接到 Selenium 的浏览器对象。

首先,您必须了解,当您创建会话键/值对(例如 'uid'=1)时,Django 的中间件将在您选择的后端(数据库、文件, 等等。)。然后,响应对象将在 cookie 中将该会话密钥发送回客户端的浏览器。当浏览器发送后续请求时,它会返回一个包含该密钥的 cookie,然后中间件使用该密钥来查找用户的会话项。

因此,解决方案需要 1.) 找到一种方法来获取在创建会话项时生成的会话密钥,然后; 2.) 找到一种方法通过 Selenium 的 Firefox webdriver 浏览器对象将该密钥传递回 cookie。这是执行此操作的代码:

selenium_test.py:
-----------------

from django.conf import settings
from django.test import LiveServerTestCase
from selenium import webdriver
from django.test.client import Client
import pdb

def create_session_store():
    """ Creates a session storage object. """

    from django.utils.importlib import import_module
    engine = import_module(settings.SESSION_ENGINE)
    # Implement a database session store object that will contain the session key.
    store = engine.SessionStore()
    store.save()
    return store

class SeleniumTestCase(LiveServerTestCase):

    def setUp(self):
        self.browser = webdriver.Firefox()
        self.browser.implicitly_wait(3)
        self.client = Client()

    def tearDown(self):
        self.browser.implicitly_wait(3)
        self.browser.quit()

    def test_welcome_page(self):
        #pdb.set_trace()
        # Create a session storage object.
        session_store = create_session_store()
        # In pdb, you can do 'session_store.session_key' to view the session key just created.

        # Create a session object from the session store object.
        session_items = session_store

        # Add a session key/value pair.
        session_items['uid'] = 1
        session_items.save()

        # Go to the correct domain.
        self.browser.get(self.live_server_url)

        # Add the session key to the cookie that will be sent back to the server.
        self.browser.add_cookie({'name': settings.SESSION_COOKIE_NAME, 'value': session_store.session_key})
        # In pdb, do 'self.browser.get_cookies() to verify that it's there.'

        # The client sends a request to the view that's expecting the session item.
        self.browser.get(self.live_server_url + '/signup/')
        body = self.browser.find_element_by_tag_name('body')
        self.assertIn('Welcome', body.text)

【讨论】:

  • 我不认为这个代码示例完成了,是吗?您实际上没有在 firefox webdriver 实例上设置任何类型的会话 cookie?
  • 在 Django 1.7+ 上你应该使用这个导入路径:from importlib import import_module(见stackoverflow.com/a/32763639
【解决方案3】:

这是我的 django==2.2 解决方案。

    from importlib import import_module
    from django.conf import settings
    from django.contrib.auth import get_user_model

    # create the session database instance
    engine = import_module(settings.SESSION_ENGINE)
    session = engine.SessionStore() 

    # create the user and instantly login
    User = get_user_model()
    temp_user = User.objects.create(username='admin')
    temp_user.set_password('password')
    self.client.login(username='admin', password='password')

    # get session object and insert data
    session = self.client.session
    session[key] = value
    session.save()
    # update selenium instance with sessionID
    selenium.add_cookie({'name': 'sessionid', 'value': session._SessionBase__session_key,
                              'secure': False, 'path': '/'})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-10
    • 2014-09-27
    • 1970-01-01
    • 2019-09-22
    • 2012-01-19
    • 2016-11-03
    • 2010-11-22
    • 1970-01-01
    相关资源
    最近更新 更多