Session key is not modified from Flask tests

拥有回忆 提交于 2019-12-09 04:33:25
  1. As this answer, as well as doc on flask.session modified attribute mention:

True if the session object detected a modification. Be advised that modifications on mutable structures are not picked up automatically, in that situation you have to explicitly set the attribute to True yourself.

So, the answer to question 1 is: it happens because list is a mutable structure and thus it's modification in session is not picked up automatically.

  1. The proper way to modify mutable structure (it doesn't matter from tests or not) is to set session.modified to True after change was done.

So, revised code for test_my_app.py would look like this:

import flask

from unittest import TestCase
import my_app

class TestApp(TestCase):

def setUp(self):
    self.test_client = my_app.app.test_client()
    self.test_client.post('/create_list/')

def testAppendList(self):
    with self.test_client as client:
        with client.session_transaction() as sess:
            sess['list'].append('3')
            sess.modified = True
        response = client.get('/in_list/')
        expected_response = "session['list'] contains '3'!".encode('ascii')
        self.assertTrue(expected_response == response.data)

Here are some cases I have found (and you might as well) interesting, which I've stumbled upon during digging around this problem:

  1. (pretty obvious one): Mutables are modified if assignment and modification happens in the same context.

So, something like this:

@app.route('/create/')
def create():
    session['example'] = ['one', 'two']
    session['example'].append('three')
    session['example'].remove('one')
    return str(session['example'])

Will return ['two', 'three']

  1. Like in the original question, in the context of modifying function the modification will be done (which could be quite misleading).

Consider the following:

@app.route('/create/')
def create():
    session['example'] = ['one', 'two']
    return str(session['example'])

@app.route('/modify/')
def modify():
    session['example'].append('four')
    return str(session['example'])

@app.route('/display/')
def display():
    return str(session['example'])

Now, running the app and accessing the following urls:

.../create/ # ['one', 'two']
.../modify/ # ['one', 'two', 'four']
.../display/ # ['one', 'two'] still
  1. Another case, that is quite confusing is when you calling render_template() at the end of your function, and appearance of the template depending on the mutable in session. In such case session is being passed into the template from current context, which is quite similar to the previous case.

Assume we have:

my_app.py

@app.route('/create/')
def create():
    session['example'] = ['one', 'two']
    return str(session['example'])

@app.route('/modify/')
def modify():
    session['example'].append('four')
    return render_template('my_template.html')

@app.route('/display/')
def display():
    return str(session['example'])

my_template.html

<!doctype html>
<html>
    <head><title>Display session['example']</title></head>
    <body>
        <div>
            {% if session['example'] %}
                {{ session['example'] }}
            {% else %}
                session['example'] is not set =(
            {% endif %}
        </div>
    </body>
</html>

Once we'll call:

.../create/ # ['one', 'two']
.../modify/ # will render page containing ['one', 'two', 'four']
.../display/ # though, still ['one', 'two']
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!