会话密钥不会从Flask测试中修改 [英] Session key is not modified from Flask tests
问题描述
session
。 这里是摘录的示例代码,用于演示问题报表,以及在测试期间打印的内容):
$ b
my_app.py
来自烧瓶导入(
烧瓶,
烧录,
)
app = Flask(__ name__)
app.secret_key ='坏密钥'
@ app.route('/ create_list /',methods = ['POST'])
def create_list ():
session ['list'] = ['1','2']
returnList created!
$ b $ app_route('/ in_list /')
def in_list():
print(str(session ['list']))#['1', '2'],但是为什么?
如果在session ['list']中输入'3':
return'session ['list'] contains'3'!
else
returnOy vey!3不在会话中['list']
test_my_app.py
import烧瓶
from unittest import TestCase
import my_app
$ b $ class TestApp(TestCase):
$ b $ def setUp(self):
self.test_client = my_app.app.test_client()
self.test_client.post('/ create_list /')
def testAppendList(self):
with self.test_client作为客户:
with client.session_transaction()as sess:
sess ['list']。append('3')
print(str(sess ['list']))# ['1','2','3'],如预期的那样
response = client.get('/ in_list /')
expected_response =session ['list'] contains'3'! .encode('ascii')
self.assertTrue(expected_response == response.data)
我的问题是:
- 为什么是t他发生了什么?
- 从测试中修改
session ['list']
的正确方法是什么? b
- As 这个答案,以及 doc
flask.session
修改
属性提及:
如果会话对象检测到修改,则为true。请注意,对可变结构的修改不会自动拾取,在这种情况下,您必须自己将该属性显式设置为True。
所以,问题1的答案是:它发生是因为list是一个可变结构,因此它在会话中的修改不会自动拾取。
- 修改可变结构的正确方法(从测试中不要紧)是将
session.modified
设置为真正
完成更改后。
因此,修改了 test_my_app.py 导入烧瓶 以下是我发现的一些情况你可能也会这么做)有趣的是,我在这个问题中偶然发现了这个问题: 所以,就像这样: 返回 请考虑以下内容: 现在,运行应用程序并访问以下网址: 假设我们有:
from unittest import TestCase
import my_app
$ b $ class TestApp(TestCase):
$ b $ def setUp(self):
self.test_client = my_app.app.test_client()
self.test_client.post('/ create_list /')
def testAppendList(self):
with se lf.test_client作为客户端:
with client.session_transaction()as sess:
sess ['list']。append('3')
sess.modified = True
response encode('ascii')
self.assertTrue(expected_response == response)= client.get('/ in_list /')
expected_response =session ['list'] contains'3'!数据)
$ b
@ app.route('/ create /')
def create():
session ['example'] = ['one', 'two']
session ['example']。append('three')
session ['example']。remove('one')
return s tr(session ['example'])
['two' ,'three']
@ 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'])
... / create /#['one','two']
... / modify /#['one','two','four']
... / display /#['one ','two']仍然是
render_template()
,以及模板的外观取决于会话中的mutable时,会非常困惑。在这种情况下, session
被从当前上下文传递到模板中,这与前面的例子非常相似。
$ b $ p my_app.py
$ b $
@ 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
$ b
<!doctype html>
< html>
< head>< title>显示会话['example']< / title>< / head>
< body>
< div>
{%if session ['example']%}
{{session ['example']}}
{%else%}
session ['example'] is not set =(
{%endif%}
< / div>
< / body>
< / html>
一旦我们打电话:
.. ./create/#['one','two']
... / modify /#会呈现包含['one','two','four']
...的页面/ display /#though,still ['one','two']
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:
- Why is this happening?
- What is the proper way to modify
session['list']
from tests?
解决方案
- 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.
- The proper way to modify mutable structure (it doesn't matter from tests or not) is to set
session.modified
toTrue
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:
- (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']
- 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
- 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 casesession
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']
这篇关于会话密钥不会从Flask测试中修改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!