Python - CherryPy 测试 - 设置会话数据?

Python - CherryPy testing - set session data?

当 运行 针对 CherryPy 服务器进行 pytest 单元测试时,使用 cherrypy.helper.CPWebCase sub-class,如何为会话对象设置数据?我试过只调用 cherrypy.session['foo']='bar' 就像我真的在一个 cherrypy 调用中一样,但这只是给了一个 "AttributeError: '_Serving' object has no attribute 'session'"

作为参考,测试用例可能看起来像这样(从 the CherryPy Docs 中提取并稍作编辑):

import cherrypy
from cherrypy.test import helper
from MyApp import Root

class SimpleCPTest(helper.CPWebCase):
    def setup_server():
        cherrypy.tree.mount(Root(), "/", {'/': {'tools.sessions.on': True}})

    setup_server = staticmethod(setup_server)

    def check_two_plus_two_equals_four(self):
        #<code to set session variable to 2 here>
        # This is the question: How do I set a session variable?
        self.getPage("/")
        self.assertStatus('200 OK')
        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
        self.assertBody('4')

处理程序可能看起来像这样(或其他任何东西,这没有任何区别):

class Root:
    @cherrypy.expose
    def test_handler(self):
        #get a random session variable and do something with it
        number_var=cherrypy.session.get('Number')
        # Add two. This will fail if the session variable has not been set,
        # Or is not a number
        number_var = number_var+2
        return str(number_var)

可以安全地假设配置是正确的,并且会话按预期工作。

当然,我可以编写一个 CherryPy 页面,将键和值作为参数,然后设置指定的会话值,并从我的测试代码中调用它(编辑:我测试过这个,它确实有效)。然而,这似乎很笨拙,如果我走那条路,我真的想将它限制为仅以某种方式进行测试。

您要实现的目标通常称为 mocking

虽然 运行ning 测试您通常希望 'mock' 您使用具有相同接口(鸭子输入)的虚拟对象访问的一些资源。这可以通过猴子修补来实现。为了简化这个过程,您可以使用 unittest.mock.patch 作为上下文管理器或 method/function 装饰器。

请在下面找到带有上下文管理器选项的工作示例:

==> MyApp.py <==

import cherrypy


class Root:
    _cp_config = {'tools.sessions.on': True}

    @cherrypy.expose
    def test_handler(self):
        # get a random session variable and do something with it
        number_var = cherrypy.session.get('Number')
        # Add two. This will fail if the session variable has not been set,
        # Or is not a number
        number_var = number_var + 2
        return str(number_var)

==> cp_test.py <==

from unittest.mock import patch

import cherrypy
from cherrypy.test import helper
from cherrypy.lib.sessions import RamSession

from MyApp import Root


class SimpleCPTest(helper.CPWebCase):
    @staticmethod
    def setup_server():
        cherrypy.tree.mount(Root(), '/', {})

    def test_check_two_plus_two_equals_four(self):
        # <code to set session variable to 2 here>
        sess_mock = RamSession()
        sess_mock['Number'] = 2
        with patch('cherrypy.session', sess_mock, create=True):
            # Inside of this block all manipulations with `cherrypy.session`
            # actually access `sess_mock` instance instead
            self.getPage("/test_handler")
        self.assertStatus('200 OK')
        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
        self.assertBody('4')

现在您可以安全地运行测试如下:

 $ py.test -sv cp_test.py
============================================================================================================ test session starts =============================================================================================================
platform darwin -- Python 3.5.2, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- ~/.pyenv/versions/3.5.2/envs/cptest-pyenv-virtualenv/bin/python3.5
cachedir: .cache
rootdir: ~/src/cptest, inifile:
collected 2 items

cp_test.py::SimpleCPTest::test_check_two_plus_two_equals_four PASSED
cp_test.py::SimpleCPTest::test_gc <- ../../.pyenv/versions/3.5.2/envs/cptest-pyenv-virtualenv/lib/python3.5/site-packages/cherrypy/test/helper.py PASSED