سؤال

I have a Flask based webapp that occasionally creates new documents with new random keys when posting to their parent document in a certain way. The new key gets in the parent's data structure, the updated parent gets temporarily stored in the session and on successfully saving the child document, the stored parent gets pulled out of the session and stored alongside, in order to link the two together. This is done for certain kinds of relations where one wants to have an inherent order between the keys, so the keys are stored as a list on the parent.

Now, the problem comes in when I want to unit test this using the Werkzeug provided unit test client. Doing a

 ret = self.test_client.post(
    request_path,
    data=data,
    follow_redirects=True
)

in the test case object will successfully redirect to the child document with the new key - but I don't know where to retrieve this new key inside the unit tests. I can't find an attribute on top of the return value that would indicate, where it has been redirected to. dir(ret) gives me

 ['__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']

Of those, headers and location look promising - however location isn't set and headers doesn't contain it either.

How can I get the redirected location from the response? Do I really have to parse the child's key from the response body? Isn't there a better way?

هل كانت مفيدة؟

المحلول 2

@bwbrowning has provided the correct hint - doing a post with follow_redirects=False the return value has the location attribute set - which is the complete request path including parameters.

edit: hint - there is a slight gotcha when doing the test_client.get(..) - the path parameter needs to be a relative path, while ret.location return the full path. so, what I did was

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)

(the child_path is used later in order to post to the child)

نصائح أخرى

Following on from your own answer, depending on your personal preference of unit test style so feel free to ignore, you may prefer something like the following suggestion to simplify and improve clarity and readability of the unit test:

# 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)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top