Ninethousand
Ninethousand

Reputation: 535

Django: Testing redirections when the target URL is also a redirection

So I'm programming a site divided in sections, which are themselves divided in subsections. In my setup, when a user clicks on the link to a section (let's say for instance '/home'), they are redirected to one of its subsections (e.g. '/home/cover'). Additionally, when a user goes to the page root, they are redirected to one of the sections (in my case '/home'). With that setup, what happens when someone goes to the root, is that they are first redirected to '/home', and from there to '/home/cover'. Those redirections are implemented like this:

Main urls.py:

from django.conf.urls import patterns, include, url
from django.views.generic.base import RedirectView

urlpatterns = patterns('',
    url(r'^$', RedirectView.as_view(url='/home')),
    url(r'^home/', include('components.home.urls', namespace='components.home')),
    ...
)

components/home/urls.py:

from django.conf.urls import patterns, include, url
from django.views.generic.base import RedirectView

from components.home import views

urlpatterns = patterns('',
    url(r'^$', RedirectView.as_view(url='cover')),
    url(r'^cover$', views.cover, name='home_cover'),
    ...
)

In practice, this seems to work fine: I can navigate my site and all the redirections do what they should. However, I can't figure out how to implement my unit tests for them, and in particular for the root redirection.

The test I designed originally was like:

def test_root_url_redirects_to_home_url(self):
    response = self.client.get('/')
    self.assertRedirects(response, '/home', status_code=301)

However, when I run it, I'm faced with the error:

"AssertionError: 301 != 200 : Couldn't retrieve redirection page '/home':
response code was 301 (expected 200)."

Now, I could easily remove all double redirections and make every redirected URL point directly to its target, but the current configuration feels cleaner and easier to maintain, so if there is some way I can properly test it that would be perfect.

I'm very new to Django and web development in general, so I'm sorry if I'm missing an obvious answer here.

Upvotes: 14

Views: 11153

Answers (2)

Babken Vardanyan
Babken Vardanyan

Reputation: 15040

By default Django's assertRedirects fetches the status code of the page and tests that it's OK. You can disable this by setting fetch_redirect_response=False:

self.assertRedirects(response, reverse('app:login'), fetch_redirect_response=False)

Upvotes: 5

Bouke
Bouke

Reputation: 12138

TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='')

Asserts that the response return a status_code redirect status, it redirected to expected_url (including any GET data), and 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.

Source: Django docs

There is no harm in double redirection (aside from the extra HTTP requests). Bearing that in mind, Django's asserting also tests the redirected-to URL if it is a local URL. The default response code that it expects is 200, but as you have a double redirect, being the 301, this fails. So in order to make the test case succeed, is to assert that the redirect also redirects:

self.assertRedirects(response, '/home', status_code=301, target_status_code=301)

Upvotes: 28

Related Questions