I'm writing detailed functional tests for my views to complement the unit tests on my models. It's a Django project and I'm using the built in Django test framework with unittest. Obviously, one of the important things to check in these functional tests is that the permissions are set up correctly. With that in mind, I'm attempting something like this:
anonclient = Client()
userclient = Client()
userclient.login(username='test_user', password='test')
adminclient = Client()
adminclient.login(username='test_admin', password='test')
path = "/path/to/my/page"
anonresponse = anonclient.get(path)
userresponse = userclient.get(path)
adminresponse = adminclient.get(path)
I need to be able to confirm that the anonclient and userclient were both denied permission while the adminclient worked correctly. Howerver, I can't find a way to test that this has happened robustly!
At first I decided to check that the response was a 302 redirect (because a side effect of failing the permission check is being redirected) but this means it is impossible to tell the difference between functionality that automatically redirects the user and a failed permissions che开发者_如何学编程ck. (I can't just use self.assertRedirects(response, url) because the target url can be overridden via the permission_required decorator's login_url parameter in the view!)
Perhaps I should look into extending the user_passes_test decorator so that it adds a property to the response object if the test fails? This could then be checked for in the tests. Failing that I will have to determine whether the request was successful by checking if the request's side-effects have happened. Doing it this way will work, but it will be extremely long winded, especially with a lot of these checks being done.
I can't imagine I am the first person to run into this issue, what's the right way to deal with this problem, or what have I missed?
Thanks very much!
The django test client returns a boolean when you call the login method, which tells you if the login was successful.
[17] >>> from django.test import Client
[18] >>> c = Client()
[19] >>> c.login(username='superuser', password='bar')
[19] : False
[20] >>> c.login(username='superuser', password='correct_password')
[20] : True
The permission_required decorator and PermissionRequiredMixin have a raise_exception
parameter.
One possible way of dealing with it is to have something like a PERMISSIONS_RAISE_EXCEPTION=True
config option in your settings_test.py
(if you are using a separate settings for test runs and have
from django.conf import settings
@permission_required('<perm>',
raise_exception=settings.PERMISSIONS_RAISE_EXCEPTION)
def your_view(...)
pass
class YourView(PermissionRequired):
raise_exception = settings.PERMISSIONS_RAISE_EXCEPTION
This way you can then catch the exception/test for the 403 in your tests and retain the redirect to the login page.
client.login('user', 'blah')
response = client.get('/yourview')
assertNot(403, response.status_code)
Adding the setting to all your permission_required
decorators might not be to your taste, it feels somewhat like your adding test code into your source, but it's the only way I have seen so far.
精彩评论