Flask 单元测试:获取响应的重定向位置
我有一个基于Flask的网页应用,它在某些情况下会创建新的文档,并为这些文档生成随机的键。当我以特定方式向父文档发送请求时,就会发生这种情况。新的键会被加入到父文档的数据结构中,更新后的父文档会暂时存储在会话中。当子文档成功保存后,存储的父文档会被取出并一起保存,以便将两者关联起来。这种做法是为了处理某些类型的关系,确保键之间有一个固有的顺序,因此这些键会作为一个列表存储在父文档中。
现在,问题出现在我想用Werkzeug提供的单元测试客户端进行单元测试时。在测试用例对象中执行一个操作
ret = self.test_client.post(
request_path,
data=data,
follow_redirects=True
)
会成功重定向到带有新键的子文档,但我不知道在单元测试中如何获取这个新键。我找不到返回值上有哪个属性可以指示它重定向到了哪里。使用dir(ret)
命令给我的结果是
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_ensure_sequence', '_get_mimetype_params', '_on_close', '_status', '_status_code', 'accept_ranges', 'add_etag', 'age', 'allow', 'autocorrect_location_header', 'automatically_set_content_length', 'cache_control', 'calculate_content_length', 'call_on_close', 'charset', 'close', 'content_encoding', 'content_language', 'content_length', 'content_location', 'content_md5', 'content_range', 'content_type', 'data', 'date', 'default_mimetype', 'default_status', 'delete_cookie', 'direct_passthrough', 'expires', 'force_type', 'freeze', 'from_app', 'get_app_iter', 'get_data', 'get_etag', 'get_wsgi_headers', 'get_wsgi_response', 'headers', 'implicit_sequence_conversion', 'is_sequence', 'is_streamed', 'iter_encoded', 'last_modified', 'location', 'make_conditional', 'make_sequence', 'mimetype', 'mimetype_params', 'response', 'retry_after', 'set_cookie', 'set_data', 'set_etag', 'status', 'status_code', 'stream', 'vary', 'www_authenticate']
在这些结果中,headers
和location
看起来很有希望,但location
没有被设置,而headers
里也没有包含它。
我该如何从响应中获取重定向的位置?难道我真的必须从响应体中解析出子文档的键吗?难道没有更好的方法吗?
2 个回答
20
接着你自己的回答,具体可以根据你个人喜欢的单元测试风格来决定,所以可以随意忽略。如果你想让单元测试更简单、更清晰、更易读,可能会更喜欢下面这个建议:
# Python 3
from urllib.parse import urlparse
# Python 2
from urlparse import urlparse
response = self.test_client.post(
request_path,
data=data,
follow_redirects=False
)
expectedPath = '/'
self.assertEqual(response.status_code, 302)
self.assertEqual(urlparse(response.location).path, expectedPath)
4
@bwbrowning 提供了正确的提示——在进行一个 POST 请求时,如果设置 follow_redirects=False
,返回的结果会有一个 location
属性,这个属性包含了完整的请求路径,包括所有的参数。
补充说明:在使用 test_client.get(..)
时,有一个小细节需要注意——路径参数需要是相对路径,而 ret.location
返回的是完整路径。所以,我做的事情是
child_path_with_parameters = rv.location.split('http://localhost')[1]
child_path = child_path_with_parameters.split('?')[0]
ret = self.test_client.get(child_path_with_parameters)
(child_path 后面会用到,用来向子路径发送请求)