0

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:

  • why the request.POST data are not passed to the view with the decorator in case of self.client.post request?
  • if anything wrong with the decorator - why then the web request works ok?
  • is it possible to keep the decorator and makeself.client.post pass the data to the view?
Mikhail Geyer
  • 881
  • 2
  • 9
  • 27
  • Does the logging get called with the client? – Daniel Roseman Mar 04 '17 at 18:51
  • Yes, the logger gets called with the client as it is initialized in the view decorator. For example, we see that in `self.client.post` there is `DEBUG: Enter foo.` in output log. – Mikhail Geyer Mar 04 '17 at 19:33
  • Actually I oversimplified the code in the question by removing `session_string = args[-1] if 'session_key' in args[-1] else '[]'` from the posted code of the decorator. I believed that this line of the code could not be the cause of the pb. And I was wrong - this line was the source of the pb. More details in my answer below. – Mikhail Geyer Mar 05 '17 at 13:26

1 Answers1

1

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.

Mikhail Geyer
  • 881
  • 2
  • 9
  • 27