Django : Testing if the page has redirected to the desired url
Asked Answered
C

5

84

In my django app, I have an authentication system. So, If I do not log in and try to access some profile's personal info, I get redirected to a login page.

Now, I need to write a test case for this. The responses from the browsers I get is :

GET /myprofile/data/some_id/ HTTP/1.1 302 0
GET /account/login?next=/myprofile/data/some_id/ HTTP/1.1 301 0
GET /account/login?next=/myprofile/data/some_id/ HTTP/1.1 200 6533

How do I write my test ? This what I have so far:

self.client.login(user="user", password="passwd")
response = self.client.get('/myprofile/data/some_id/')
self.assertEqual(response.status,200)
self.client.logout()
response = self.client.get('/myprofile/data/some_id/')

What could possibly come next ?

Convolvulus answered 19/2, 2013 at 6:41 Comment(0)
H
137

Django 1.4:

https://docs.djangoproject.com/en/1.4/topics/testing/#django.test.TestCase.assertRedirects

Django 2.0:

https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects

SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='', fetch_redirect_response=True)

Asserts that the response returned a status_code redirect status, redirected to expected_url (including any GET data), and that the final page was received with target_status_code.

If your request used the follow argument, the expected_url and target_status_code will be the url and status code for the final point of the redirect chain.

If fetch_redirect_response is False, the final page won’t be loaded. Since the test client can’t fetch external URLs, this is particularly useful if expected_url isn’t part of your Django app.

Scheme is handled correctly when making comparisons between two URLs. If there isn’t any scheme specified in the location where we are redirected to, the original request’s scheme is used. If present, the scheme in expected_url is the one used to make the comparisons to.

Harmsworth answered 19/2, 2013 at 9:27 Comment(0)
O
60

You could also follow the redirect with:

response = self.client.get('/myprofile/data/some_id/', follow=True)

which would mirror the user experience in the browser and make assertions of what you expect to find there, such as:

self.assertContains(response, "You must be logged in", status_code=401)
Orling answered 29/10, 2013 at 18:28 Comment(1)
Expecting specific page content in a test is dangerous. Makes it possible that non-programmers (webpage editors) can unknowingly break the tests.Runck
S
39

You can check response['Location'] and see if it matchs with the expected url. Check also that status code is 302.

Sawdust answered 19/2, 2013 at 6:45 Comment(2)
Best for when one doesn't care what target_status_code will be.Verb
When doing unit tests on the Views directly (without using the Django client), this is the correct answer.Madness
M
16

response['Location'] doesn't exist in 1.9. Use this instead:

response = self.client.get('/myprofile/data/some_id/', follow=True)
last_url, status_code = response.redirect_chain[-1]
print(last_url)
Mounting answered 16/8, 2016 at 16:19 Comment(2)
It is available if follow=True is not provided. Django (any version) does not remove normal response headers like Location. When follow is True, the redirects are followed and naturally the last response has no Location header.Wrap
I confirm that Amir is correct (Django 1.11.8), which allows for checking for redirection with self.assertRedirects (or the status_code) and check the redirection location.Nigritude
P
3

You can use assertRedirects eg:

response = self.client.get('/sekrit/')
self.assertRedirects(response, '/other/login/?next=/sekrit/')

https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects

If you need to get url which redirected

If follow is True

You will get url in

response.redirect_chain[-1]

If follow is False

response.url
Pender answered 11/1, 2021 at 7:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.