问题
I'm doing some (isolated) unit test for a view which is decorated with "login_required". Example:
@login_required
def my_view(request):
return HttpResponse('test')
Is it possible to test that the "my_view" function is decorated with "login_required"?
I know I can test the behaviour (anonymous user is redirected to login page) with an integration test (using the test client) but I'd like to do it with an isolated test.
Any idea?
Thanks!
回答1:
Sure, it must be possible to test it in some way. It's definitely not worth it, though. Writing a fully isolated unit test to check that the decorator is applied will only result in a very complicated test. There is a way higher chance that the test will be wrong than that the tested behaviour is wrong. I would strongly discourage it.
The easiest way to test it is to use Django's Client
to fake a request to the associated url, and check for a redirect. If you're using any of Django's testcases as your base class:
class MyTestCase(django.test.TestCase):
def test_login_required(self):
response = self.client.get(reverse(my_view))
self.assertRedirects(response, reverse('login'))
A slightly more complicated, but a bit more isolated test would be to call the view directly using the RequestFactory to create a request object. assertRedirects()
won't work in this case, since it depends on attributes set by the Client
:
from django.test.client import RequestFactory
class MyTestCase(django.test.TestCase):
@classmethod
def setUpClass(cls):
super(MyTestCase, cls).setUpClass()
self.rf = RequestFactory()
def test_login_required(self):
request = self.rf.get('/path/to/view')
response = my_view(request, *args, **kwargs)
self.assertEqual(response.status_code, 302)
self.assertEqual(response['Location'], login_url)
...
回答2:
Use Django's Test Client to check for proper redirects in case a user is loggedin and when not loggedin.
from django.test import TestCase
from django.core.urlresolvers import reverse
class TestLoginRequired(django.test.TestCase):
def test_redirects_to_login_page_on_not_loggedin(self):
response = self.client.get(reverse(my_view))
self.assertRedirects(response, reverse('login_page'))
def test_redirects_to_test_page_on_loggedin(self):
self.client.login(username='my_username', password='my_password')
response = self.client.get(reverse(my_view))
self.assertRedirects(response, reverse('test'))
MOCK Library:
For an isolated test or 'pure' unit testing, you can use the mock module.
Mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used.
Mock is based on the ‘action -> assertion’ pattern instead of ‘record -> replay’ used by many mocking frameworks.
You will have to create a mock object. Mock objects create all attributes and methods as you access them and store details of how they have been used. You can configure them, to specify return values or limit what attributes are available, and then make assertions about how they have been used:
The tests with mock objects will test only whether my_view
function is decorated with login_required
. You don't need to setup other attributes.
Check out the docs on how to write tests using mock objects using this link.
Also, following SO links might help on how to monkey-patch a decorator.
- How can I monkey-patch a decorator in Django's models while testing?
- Can I patch a Python decorator before it wraps a function?
回答3:
Using requests
library, if you don't pass it a auth cookie you can test that login is required based on whether it returns 401/403/200/whatever
import requests
req = requests.get("http://yoururl.com")
if req.status_code ==200:
print "login not needed apparently"
else:
print "check for other status codes or redirect"
来源:https://stackoverflow.com/questions/30948563/how-to-test-if-a-view-is-decorated-with-login-required-django