在django测试中设置会话变量

时间:2014-08-05 06:41:59

标签: django django-testing

这有效

def test_access_to_home_with_location(self):
    self.client.login(username=self.user.get_username(), password='pass')
    session = self.client.session
    session['location'] = [42]
    session.save()
    response = self.client.get(reverse('home'))

但是这个

def test_access_to_home_with_location(self):
    session = self.client.session
    session['location'] = [42]
    session.save()
    response = self.client.get(reverse('home'))

打破

====================================================================== 
ERROR: test_access_to_home_with_location (posts.tests.HomeViewTestCase)       
----------------------------------------------------------------------      
Traceback (most recent call last):                                            
  File "tests.py", line 32, in test_access_to_home_with_location                            
    session.save()                                                              
AttributeError: 'dict' object has no attribute 'save'

所以似乎没有调用self.client.login() self.client.session只是一个空字典。有没有办法将其初始化为会话对象?

4 个答案:

答案 0 :(得分:7)

如果客户端没有设置cookie,则session属性为空字典,因此您的错误。以下是django.test.client.Client的相关来源:

def _session(self):
    """
    Obtains the current session variables.
    """
    if 'django.contrib.sessions' in settings.INSTALLED_APPS:
        engine = import_module(settings.SESSION_ENGINE)
        cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
        if cookie:
            return engine.SessionStore(cookie.value)
    return {}
session = property(_session)

由于您未使用匹配settings.SESSION_COOKIE_NAME的密钥登录cookie,因此未找到。

但是你可以手动创建一个这样的会话对象:

if not self.client.session:
    engine = import_module(settings.SESSION_ENGINE)

    self.client.session = engine.SessionStore()
    self.client.session.save()

这是loginClient处理程序创建新会话的方式。

编辑:我意识到您还需要将会话密钥保存在Cookie中,以便下一个请求使用相同的会话

这是一个辅助函数,你可以放在Client子类中创建一个新会话和一个引用cookie:

def set_session_data(self, key, value):
    """Shortcut for setting session data regardless of being authenticated"""

    if not self.client.session:
        # Save new session in database and add cookie referencing it

        engine = import_module(settings.SESSION_ENGINE)

        self.client.session = engine.SessionStore()
        self.client.session.save()

        session_cookie = settings.SESSION_COOKIE_NAME
        self.client.cookies[session_cookie] = self.client.session.session_key
        cookie_data = {
            'max-age': None,
            'path': '/',
            'domain': settings.SESSION_COOKIE_DOMAIN,
            'secure': settings.SESSION_COOKIE_SECURE or None,
            'expires': None,
        }
        self.client.cookies[session_cookie].update(cookie_data)

    self.client.session[key] = value
    self.client.session.save()

注意:我不是说这是唯一的方法,这是我通过阅读django源代码发现的一种方式。此答案中的代码未经过测试/运行,因此可能需要进行一些微调。

进一步阅读

要了解SessionStore的工作原理,您可以查看django.contrib.sessions模块。

要了解如何在Client中处理会话和Cookie,您可以查看django.test.client.Client

答案 1 :(得分:3)

rzetterberg答案是更严格的答案,所以我认为它应该保持被接受,但这种方式看起来也会起作用

def setUp(self):
    """
    set up sessions for anonymous users
    """
    engine = import_module(settings.SESSION_ENGINE)
    store = engine.SessionStore()
    store.save()  
    self.client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key

看起来这个主题上有一张当前的票据(5年前开始......但在最近几个月内有效):
https://code.djangoproject.com/ticket/10899

https://code.djangoproject.com/ticket/11475

答案 2 :(得分:3)

请注意,不再需要解决方法。原始问题的片段不起作用现在应该有效:

session = self.client.session
session['location'] = [42]
session.save()

https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.Client.session

答案 3 :(得分:0)

我使用RequestFactory生成request对象,手动设置会话值,并将其传递给视图函数,如docs中所示。

from django.test import TestCase, RequestFactory
from django.urls import reverse

from .views import test_view

class MyTestCase(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    def test_view_x(self):
        request = self.factory.get(reverse('myapp:test_view'))
        request.session = {'foo': 'bar'}

        response = test_view(request)

        ...

        # Run some test on the response to ensure the view is returning
        # the expected value

使用RequestFactory生成请求对象可以测试视图函数,就像测试任何其他函数一样 - 将其视为黑盒子,传递某些输入并检查正确的输出。请注意,您单独运行请求,没有任何已安装的中间件。