I have a simple test case which checks that POST
request with valid data returns an HTML response with 200 status code:
class PostRequestTestCase(TestCase):
def test_valid_post_request(self):
response = self.client.post('/foo/', data={'text': 'bar'})
self.assertEqual(response.status_code, 200)
Here is the view foo
which is triggered for that request:
logger = logging.getLogger(__name__)
# decorator to trace enter and exit events
enter_exit_tracer = enter_exit_Tracer(logger)
@enter_exit_tracer
def foo(request):
if request.method == 'POST':
#
print('request.POST:', request.POST)
#
# some stuff
where @enter_exit_tracer
is a decorator to trace entering/exiting a function:
def enter_exit_Tracer(logger):
def middle(f):
def inner(*args, **kwargs):
session_string = args[-1] if 'session_key' in args[-1] else '[]'
logger.debug('%s Enter %s.', session_string, f.__name__)
result = f(*args, **kwargs)
logger.debug('%s Exit %s.', session_string, f.__name__)
return result
return inner
return middle
It turns out that when I add this decorator to foo
function, then the POST
data sent via self.client.post
are actually not passed to foo
. They are missing in the test request - so my test fails:
DEBUG: [] Enter foo.
request.POST: <QueryDict: {}>
ERROR: Invalid form
F
======================================================================
FAIL: test_valid_post_request (textstat.tests.PostRequestTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/user/Pro/myapp/tests.py", line 111, in test_valid_post_request
self.assertEqual(response.status_code, 200)
AssertionError: 400 != 200
----------------------------------------------------------------------
Ran 1 test in 0.018s
FAILED (failures=1)
We see request.POST: <QueryDict: {}>
and eventually this leads to ERROR: Invalid form
.
At the same time when I do the similar POST
request but via a web browser everything works fine - the form gets populated with data, the web page is rendered ok and @enter_exit_tracer
does its logging as expected.
If I comment out @enter_exit_tracer
decorator then everything works also ok and the test is passed:
request.POST: <QueryDict: {'text': ['bar']}>
.
----------------------------------------------------------------------
Ran 1 test in 0.007s
OK
The questions:
request.POST
data are not passed to the view with the decorator in case of self.client.post
request?self.client.post
pass the data to the view?It turns out that the decorator has a TypeError
error in this line:
session_string = args[-1] if 'session_key' in args[-1] else '[]'
So when args[-1]
is not str
then this should not work. Fixing it with str(args[-1])
resolves the whole issue with missing POST
data.
It is weird though that self.client.post
does not raise any TypeError
and session_string
was somehow calculated. Instead of this POST
data were not sent to the view without any errors or hint warnings. POST
data were just disappeared. At the same time the same code worked ok when POST
request was sent from web browser, so the error remained unnoticed.