I have a view that is supposed to redirect to /accounts/login/?next=/amos/
when a user tries to access /amos
when they aren't logged in. In order to do test for this, I use the following test:
import urllib
# I actually define this function elsewhere, I placed it here for brevity's sake
def url_with_querystring(path, **kwargs):
return path + '?' + urllib.urlencode(kwargs)
def setUp(self):
self.client = Client()
def test_call_view_denies_anonymous(self):
target_url = reverse('amos_index')
redirect_url = url_with_querystring(reverse('login'), next='/amos/')
response = self.client.get(target_url, follow=True)
self.assertRedirects(response, redirect_url)
response = self.client.post(target_url, follow=True)
self.assertRedirects(response, redirect_url)
The error occurs with self.assertRedirects(response, redirect_url)
. Specifically, it raises this error:
AssertionError: Response redirected to '/accounts/login/?next=/amos/', expected '/accounts/login/?next=%2Famos%2F'
Obviously, the error comes from /
not being equal to %2F
. The redirect URL returned by response
seems to just be a raw string, while the self-defined function returns a properly URL-encoded string. What should I do in this case? Should I just not URL-encode it or is this an issue with django.test.client
?
EDIT: I've read a previously raised bug over at the DjangoProject website. From what I understood, it seems that this is intended behaviour? That is, within Django's internal systems, URLs are not encoded. Would like some insight from more experienced people, thank you!
If you look at Django's redirect_to_login
method, which is used by the decorators like login_required
, you can see that it treats forward slashes as a safe character and doesn't encode them.
login_url_parts[4] = querystring.urlencode(safe='/')
You could mimic this behaviour in your test. However, I think it would be easiest to simply not urlencode the string. The important thing to test is that anonymous users are redirected. There should already be tests in Django to make sure that the url is encoded appropriately, so I'm not sure there's much to gain by repeating this.
redirect_url = reverse('login') + '?next=/amos/'