如何在Django测试框架中修改会话(session)

39
我的网站允许未登录的个人通过创建基于当前session_key的用户来贡献内容。
我想为我的视图设置一个测试,但似乎无法修改request.session:
我想这样做:
from django.contrib.sessions.models import Session
s = Session()
s.expire_date = '2010-12-05'
s.session_key = 'my_session_key'
s.save()
self.client.session = s
response = self.client.get('/myview/')

但我遇到了错误:

AttributeError: can't set attribute

如何在发出get请求之前修改客户端会话的想法? 我看到了这个,但它似乎不起作用。


session 是一个类似于字典的对象,你应该使用 s[x] 来获取和设置值。 - xj9
5个回答

71

Django 测试框架的客户端对象可以访问 session。请参考http://docs.djangoproject.com/en/dev/topics/testing/?from=olddocs#django.test.client.Client.session以获取更多详情。

要注意:若想修改并保存 session,则必须先将其存储在变量中(因为每次访问该属性时都会创建一个新的 SessionStore)

我认为以下代码应该能够实现目的:

s = self.client.session
s.update({
    "expire_date": '2010-12-05',
    "session_key": 'my_session_key',
})
s.save()
response = self.client.get('/myview/')

8
嗨 Luc,感谢您的帮助,但这不起作用。我收到以下错误:AttributeError: 'dict' object has no attribute 'save'这是因为client.session对象是一个字典。似乎只有在请求被发出后(仅当用户登录时),client.session才会成为真正的Session对象。还有其他建议吗?您可以通过输入以下内容来重复此操作(从shell中): from django.test import Client client = Client() s = client.session s['expire_date']='2010-12-05' s['session_key']='my_session_key' s.save() - Riley
5
Luc建议的方法看起来可行,但这是一个Django的bug:https://code.djangoproject.com/ticket/11475。 - Andrew
1
给安德鲁加1——这个bug似乎至少存在了4年。 - lsh
关于前两个评论,我相信这个错误已经在以下 提交中得到修复。 - x-yuri
这对我有用。看起来上面其他人评论的错误已经被修复了。 - Code-Apprentice
首先将会话保存到一个变量中,解决了我的问题。 - inostia

38

以下是我如何完成的(启发自http://blog.mediaonfire.com/?p=36中的解决方案)。

from django.test import TestCase
from django.conf import settings
from django.utils.importlib import import_module

class SessionTestCase(TestCase):
    def setUp(self):
        # http://code.djangoproject.com/ticket/10899
        settings.SESSION_ENGINE = 'django.contrib.sessions.backends.file'
        engine = import_module(settings.SESSION_ENGINE)
        store = engine.SessionStore()
        store.save()
        self.session = store
        self.client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key

之后,您可以按照以下方式创建测试:

class BlahTestCase(SessionTestCase):

    def test_blah_with_session(self):
        session = self.session
        session['operator'] = 'Jimmy'
        session.save()

etc...


这个还能在Django 1.6中使用Pickle序列化器(而不是现在标准的JSONSerializer用于SESSION_SERIALIZER)吗? - Toran Billups

14

正如Andrew Austin已经提到的,它无法工作是因为这个错误: https://code.djangoproject.com/ticket/11475

不过你可以这样做:

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

class SessionTestCase(TestCase):
    def setUp(self):
        self.client = Client()
        User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
        self.client.login(username='john', password='johnpassword')

    def test_something_with_sessions(self):
        session = self.client.session
        session['key'] = 'value'
        session.save()

使用User.objects.create_user()和self.client.login()创建并登录用户后,如上面的代码所示,会话应该正常工作。

3
根据文档,你可以通过以下方式在测试客户端中向会话添加值:例如
def test_something(self):
    session = self.client.session
    session['somekey'] = 'test'
    session.save()

https://docs.djangoproject.com/zh-hans/dev/topics/testing/tools/#django.test.Client.session

使用此功能将允许您测试需要数据存储在会话中才能正常运行的视图。

因此,对于此问题:

session = self.client.session
   session['expire_date'] = '2010-12-05'
   .....
   session.save()

3
你可以创建一个自定义视图,插入虚拟数据,例如会话。
对应URL的视图为:/dummy/:
def dummy(request):
    # dummy init data
    request.session['expiry_date'] = '2010-12-05'
    return HttpResponse('Dummy data has been set successfully')

在测试脚本中,只需调用self.client.get('/dummy/')

我还使用这个虚拟视图来手动测试时初始化会话中的虚拟数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接