在django测试中设置会话变量

Ben*_*Ben 11 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'))
Run Code Online (Sandbox Code Playgroud)

但是这个

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

打破

====================================================================== 
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'
Run Code Online (Sandbox Code Playgroud)

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

rze*_*erg 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)
Run Code Online (Sandbox Code Playgroud)

由于您未登录cookie,因此settings.SESSION_COOKIE_NAME找不到密钥匹配.

但是,您可以手动创建这样的会话对象:

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

    self.client.session = engine.SessionStore()
    self.client.session.save()
Run Code Online (Sandbox Code Playgroud)

这是login处理程序Client创建新会话的方式.

编辑:我意识到你还需要将会话密钥保存在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()
Run Code Online (Sandbox Code Playgroud)

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

进一步阅读

阅读有关如何SessionStore工作的内容,您可以查看该django.contrib.sessions模块.

要了解如何处理会话和cookie,Client请查看django.test.client.Client.

  • 我很惊讶这是一项艰巨的任务。似乎是通常需要的东西。有没有更好的方法来进行这种测试? (2认同)

Bra*_*mul 5

请注意,不再需要解决方法。原来无效的问题代码段现在应该可以正常工作:

session = self.client.session
session['location'] = [42]
session.save()
Run Code Online (Sandbox Code Playgroud)

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

  • 我相信它已在[以下](https://code.djangoproject.com/ticket/21357)[提交](https://github.com/django/django/commit/be88b062afaa58559bb12623e8ed8843f07b97a1#diff-97160f50594424a40f2621d5a3c中修复581ccR396)。确保在进行更改之前将 session 放入变量中,就像答案中一样,因为每次编写 `self.client.session` 时,您都会得到 [新对象](https://github.com/django/django/blob/2.2 /django/test/client.py#L452-L463)。 (2认同)