Performance testing web applications is a little tricky when we want to test features accessible only to logged in users. Automated test recorders intercept session cookies and hardcode them into test scenarios. When we run these tests later, different session IDs are generated and recorded cookie values don’t grant access anymore. This text demonstrates how to write a scenario for The Grinder to test a Django application. Tests include user login, submitting CSRF-protected forms and AJAX requests.
Test scenario example
Let’s dive right in. The code below is a sample test scenario for The Grinder. It represents various aspects of interaction between the test agent and your application including:
- logging a user in
- accessing password protected pages and API calls:
- GETting a page
- submitting a CSRF-protected form
- sending an AJAX
XMLHttpRequest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
|
How does it work?
Django as well as many other web applications use a simple authentication mechanism. First, the user provides a username and password combination. The application then verifies user data, opens a session and sends a session cookie back to the user. A session ID contained in the cookie uniquely identifies the user’s open session. As long as each request from the user comes in accompanied by the cookie, the user is considered logged in, at least until the session expires on the server.
The example test scenario file above depends on The Grinder’s ability to parse and resubmit cookies, so you don’t actually have to worry about the sessionid
cookie.
A note on CSRF tokens and testing AJAX methods
Another obstacle to overcome when running automated tests on Django are anti cross-site request forgery tokens. These tokens are generated dynamically for every form and Django requires that they be submitted with every POST request.
In the example test scenario we don’t parse HTML forms, but instead rely on the fact that Django also sets a cookie with the CSRF token value. We fetch the cookie value (using the get_csrf_token
function) and submit it as a field named csrfmiddlewaretoken
in POST data.
1 2 3 4 5 |
|
We can also simulate AJAX requests by sending appropriate headers, namely X-Requested-With
and X-CSRFToken
. The anti-CSRF token value is read from cookie and written in the latter header.
1 2 3 4 |
|
If you’re still having trouble with CSRF and keep testing 403 errors instead of your application, you can disable CSRF completely using a small bit of middleware. Just make sure you don’t leave this on in production.
1 2 3 |
|
Final result
When your tests are prepared and properly vetted you can leverage the power of The Grinder to run them from as many parallel agent machines (and/or threads) as you require. Your test output will include execution time statistics for every test step.
