Created
May 13, 2014 23:39
-
-
Save timhughes/8e56c2955d3baa3fa2ca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from urllib.parse import urlparse | |
from django.contrib.auth import get_user_model | |
from django.core.urlresolvers import reverse | |
from django.test import TestCase | |
class ViewTestMixin(object): | |
"""the name of the url to access the view. If you provide url, then it will take precedence.""" | |
view_urlname = None | |
"""The path to the template for the view.""" | |
view_template = None | |
"""The url to access the view. You can provide this or urlname. This takes precedence.""" | |
view_url = None | |
def __init__(self, *args, **kwargs): | |
assert (self.view_urlname is not None) or (self.view_url is not None), "You must provide an urlname or an url." | |
if self.view_url is None and self.view_urlname is not None: | |
self.view_url = reverse(self.view_urlname) | |
super(ViewTestMixin, self).__init__(*args, **kwargs) | |
def test_view_loads(self): | |
self._login() | |
response = self.client.get(self.view_url) | |
self.assertEqual(response.status_code, 200) | |
self.assertTemplateUsed(response, self.view_template) | |
def _login(self): | |
# See if LoginRequiredViewTestMixin is present, and if so, login | |
try: | |
self.login() | |
except AttributeError: | |
return | |
class FormViewTestMixin(object): | |
"""The name of the form in the context.""" | |
form_context_name = None | |
"""A list of field names that _require_ data.""" | |
form_required_fields = [] | |
"""A mapping of field names to _invalid_ data for those fields. Optional since """ | |
form_invalid_data = None | |
"""A mapping of field names to _valid_ data for those fields.""" | |
form_valid_data = None | |
"""The name of the url that the view redirects to on succesful post.""" | |
form_success_redirect_name = None | |
"""Instead of provding a form_success_redirect_name, you can provide the url path. | |
If you provide form_success_redirect_url, it takes precedence over form_success_redirect_name""" | |
form_success_redirect_url = None | |
def __init__(self, *args, **kwargs): | |
# Check that ViewTestMixin is present | |
assert getattr(self, 'view_url', False), "FormViewTestMixin requires ViewTestMixin" | |
# Check required fields | |
err_msg = ' must be provided' | |
assert self.form_context_name is not None, 'form_context_name' + err_msg | |
assert self.form_invalid_data is not None, 'form_invalid_data' + err_msg | |
assert self.form_valid_data is not None, 'form_valid data' + err_msg | |
# Make sure we have either a name or url for redirects | |
assert (self.form_success_redirect_name is not None) or \ | |
(self.form_success_redirect_url is not None), \ | |
"You must provide form_success_redirect_name or form_success_redirect_url." | |
if self.form_success_redirect_url is None and self.form_success_redirect_name is not None: | |
self.form_success_redirect_url = reverse(self.form_success_redirect_name) | |
super(FormViewTestMixin, self).__init__(*args, **kwargs) | |
def _login(self): | |
# See if LoginRequiredViewTestMixin is present, and if so, login | |
try: | |
self.login() | |
except AttributeError: | |
return | |
def test_view_fails_blank_post(self): | |
self._login() | |
response = self.client.post(self.view_url, {}) | |
if self.form_context_name and self.form_required_fields: | |
for req_field in self.form_required_fields: | |
self.assertFormError(response, self.form_context_name, req_field, 'This field is required.') | |
def test_view_fails_invalid_post(self): | |
if self.form_context_name and self.form_invalid_data: | |
self._login() | |
response = self.client.post(self.view_url, ) | |
for field_name, invalid_field in self.form_invalid_data.items(): | |
self.assertFormError(response, self.form_context_name, field_name, | |
'This needs to be a different error message') | |
def test_view_succesful_post(self): | |
if self._success_url and self.form_valid_data: | |
self._login() | |
response = self.client.post(self.view_url, self.form_valid_data) | |
self.assertRedirects(response, self._success_url) | |
class LoginRequiredViewTestMixin(object): | |
"""The name of the url where login-required views will redirect to for anonymous users. | |
Typically this would be the view for logging in.""" | |
login_urlname = None | |
"""The url path that the view redirects to for anonymous users. If both this and login_urlname | |
are provided, this takes precedence""" | |
login_url = None | |
def __init__(self, *args, **kwargs): | |
assert (self.login_url is not None) or (self.login_urlname is not None), \ | |
"You must provide login_urlname or login_url" | |
if self.login_url is None and self.login_urlname is not None: | |
self.login_url = reverse(self.login_urlname) | |
super(LoginRequiredViewTestMixin, self).__init__(*args, **kwargs) | |
def assertRedirectsToLogin(self, response): | |
"""AFAIK, this just works with django-allauth as it specifically checks for | |
the `next` parameter on the login url.""" | |
assert getattr(response, 'redirect_chain', False), "No redirecting done." | |
parsed = urlparse(response.redirect_chain[-1][0]) | |
domainy = "{}://{}".format(parsed.scheme, parsed.netloc) | |
url = "{}{}?next={}".format(domainy, self.login_url, self.view_url) | |
self.assertRedirects(response, url) | |
def login(self): | |
pw = 'ja;sdoijfl' | |
username = 'fdsa09ujids' | |
self.user = get_user_model().objects.create(username=username, password='1234') | |
self.user.set_password(pw) | |
self.user.save() | |
login = self.client.login(username=username, password=pw) | |
self.assertTrue(login) | |
def test_view_denies_anonymous(self): | |
if self.login_urlname: | |
response = self.client.get(self.view_url, follow=True) | |
self.assertRedirectsToLogin(response) | |
response = self.client.post(self.view_url, follow=True) | |
self.assertRedirectsToLogin(response) | |
# Here's a test case for a view that requires a login | |
class DashViewTest(ViewTestMixin, LoginRequiredViewTestMixin, TestCase): | |
view_urlname = 'dashboard' | |
view_template = 'core/dashboard.html' | |
login_urlname = 'account_login' | |
# Here's a test for a view that has no forms and doesn't require a login | |
class HomeViewTest(ViewTestMixin, TestCase): | |
view_urlname = 'home' | |
view_template = 'general/index.html' | |
# Here's a test case for a view that has a form and requires a login | |
class PersonCreatePageTest(ViewTestMixin, LoginRequiredViewTestMixin, FormViewTestMixin, ORMTest): | |
view_urlname = 'person_create' | |
view_template = 'property/property_form.html' | |
login_urlname = 'account_login' | |
form_context_name = 'form' | |
form_required_fields = ['name', 'address1', 'city', 'state', 'zipcode'] | |
form_invalid_data = {'name': 'a' * 300, | |
'address1': 'b' * 300, | |
'city': 'd' * 300, | |
'zipcode': '1', | |
'state': 'not a state here'} | |
form_valid_data = {'name': 'a name', | |
'address1': '123 Address', | |
'address2': 'Apt. 17', | |
'city': 'The City', | |
'zipcode': '12345-1234', | |
'state': 'CA'} | |
form_success_redirect_name = 'person_list' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment