Reputation:
I am building a tests for my Flask application, in one of the test there is a need to modify a session key (which itself is a list of values), and then check that app behaviour is altered by the modified key content. I'm using an approach from Flask documentation for modifying session
from tests.
Here is an excerpt example code, to demonstrate the problem (I have added print statements, along with what they are printing during test run):
my_app.py
from flask import (
Flask,
session,
)
app = Flask(__name__)
app.secret_key = 'bad secret key'
@app.route('/create_list/', methods=['POST'])
def create_list():
session['list'] = ['1', '2']
return "List created!"
@app.route('/in_list/')
def in_list():
print(str(session['list'])) # ['1', '2'], but why?
if '3' in session['list']:
return "session['list'] contains '3'!"
else:
return "Oy vey! '3' is not in the session['list']"
test_my_app.py
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')
print(str(sess['list'])) # ['1', '2', '3'], as expected
response = client.get('/in_list/')
expected_response = "session['list'] contains '3'!".encode('ascii')
self.assertTrue(expected_response == response.data)
My questions are:
session['list']
from tests?Upvotes: 1
Views: 1312
Reputation:
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.
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:
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']
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
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']
Upvotes: 4