Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added assertFormError, assertTemplateUsed and assertTemplateNotUsed f…

…or use during unit testing.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@5156 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f073797f4ca8d3e2736d99f76674e43640399c0d 1 parent 64adc41
@freakboy3742 freakboy3742 authored
View
60 django/test/testcases.py
@@ -77,4 +77,62 @@ def assertContains(self, response, text, count=1):
real_count = response.content.count(text)
self.assertEqual(real_count, count,
"Could only find %d of %d instances of '%s' in response" % (real_count, count, text))
-
+
+ def assertFormError(self, response, form, field, errors):
+ "Assert that a form used to render the response has a specific field error"
+ if not response.context:
+ self.fail('Response did not use any contexts to render the response')
+
+ # If there is a single context, put it into a list to simplify processing
+ if not isinstance(response.context, list):
+ contexts = [response.context]
+ else:
+ contexts = response.context
+
+ # If a single error string is provided, make it a list to simplify processing
+ if not isinstance(errors, list):
+ errors = [errors]
+
+ # Search all contexts for the error.
+ found_form = False
+ for i,context in enumerate(contexts):
+ if form in context:
+ found_form = True
+ try:
+ for err in errors:
+ if field:
+ self.assertTrue(err in context[form].errors[field],
+ "The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" %
+ (field, form, i, err, list(context[form].errors[field])))
+ else:
+ self.assertTrue(err in context[form].non_field_errors(),
+ "The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" %
+ (form, i, err, list(context[form].non_field_errors())))
+ except KeyError:
+ self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field))
+ if not found_form:
+ self.fail("The form '%s' was not used to render the response" % form)
+
+ def assertTemplateUsed(self, response, template_name):
+ "Assert that the template with the provided name was used in rendering the response"
+ if isinstance(response.template, list):
+ template_names = [t.name for t in response.template]
+ self.assertTrue(template_name in template_names,
+ "Template '%s' was not one of the templates used to render the response. Templates used: %s" %
+ (template_name, template_names))
+ elif response.template:
+ self.assertEqual(template_name, response.template.name,
+ "Template '%s' was not used to render the response. Actual template was '%s'" %
+ (template_name, response.template.name))
+ else:
+ self.fail('No templates used to render the response')
+
+ def assertTemplateNotUsed(self, response, template_name):
+ "Assert that the template with the provided name was NOT used in rendering the response"
+ if isinstance(response.template, list):
+ self.assertFalse(template_name in [t.name for t in response.template],
+ "Template '%s' was used unexpectedly in rendering the response" % template_name)
+ elif response.template:
+ self.assertNotEqual(template_name, response.template.name,
+ "Template '%s' was used unexpectedly in rendering the response" % template_name)
+
View
31 docs/testing.txt
@@ -462,15 +462,36 @@ Normal Python unit tests have a wide range of assertions, such as
``django.TestCase`` adds to these, providing some assertions
that can be useful in testing the behavior of web sites.
-``assertRedirects(response, expected_path)``
- Assert that the response received redirects the browser to the provided
- path, and that the expected_path can be retrieved.
-
``assertContains(response, text, count=1)``
- Assert that a response indicates that a page was retreived successfully,
+ Assert that a response indicates that a page was retrieved successfully,
(i.e., the HTTP status code was 200), and that ``text`` occurs ``count``
times in the content of the response.
+``assertFormError(response, form, field, errors)``
+ Assert that a field on a form raised the provided list of errors when
+ rendered on the form.
+
+ ``form`` is the name the form object was given in the template context.
+
+ ``field`` is the name of the field on the form to check. If ``field``
+ has a value of ``None``, non-field errors will be checked.
+
+ ``errors`` is an error string, or a list of error strings, that are
+ expected as a result of form validation.
+
+``assertTemplateNotUsed(response, template_name)``
+ Assert that the template with the given name was *not* used in rendering
+ the response.
+
+``assertRedirects(response, expected_path)``
+ Assert that the response received redirects the browser to the provided
+ path, and that the expected_path can be retrieved.
+
+``assertTemplateUsed(response, template_name)``
+ Assert that the template with the given name was used in rendering the
+ response.
+
+
Running tests
=============
View
74 tests/modeltests/test_client/models.py
@@ -33,6 +33,13 @@ def test_get_view(self):
self.assertEqual(response.context['var'], 42)
self.assertEqual(response.template.name, 'GET Template')
+ def test_no_template_view(self):
+ "Check that template usage assersions work then templates aren't in use"
+ response = self.client.get('/test_client/no_template_view/')
+
+ # Check that the no template case doesn't mess with the template assertions
+ self.assertTemplateNotUsed(response, 'GET Template')
+
def test_get_post_view(self):
"GET a view that normally expects POSTs"
response = self.client.get('/test_client/post_view/', {})
@@ -40,6 +47,8 @@ def test_get_post_view(self):
# Check some response details
self.assertEqual(response.status_code, 200)
self.assertEqual(response.template.name, 'Empty GET Template')
+ self.assertTemplateUsed(response, 'Empty GET Template')
+ self.assertTemplateNotUsed(response, 'Empty POST Template')
def test_empty_post(self):
"POST an empty dictionary to a view"
@@ -48,6 +57,8 @@ def test_empty_post(self):
# Check some response details
self.assertEqual(response.status_code, 200)
self.assertEqual(response.template.name, 'Empty POST Template')
+ self.assertTemplateNotUsed(response, 'Empty GET Template')
+ self.assertTemplateUsed(response, 'Empty POST Template')
def test_post(self):
"POST some data to a view"
@@ -88,7 +99,7 @@ def test_valid_form(self):
}
response = self.client.post('/test_client/form_view/', post_data)
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.template.name, "Valid POST Template")
+ self.assertTemplateUsed(response, "Valid POST Template")
def test_incomplete_data_form(self):
"POST incomplete data to a form"
@@ -97,8 +108,13 @@ def test_incomplete_data_form(self):
'value': 37
}
response = self.client.post('/test_client/form_view/', post_data)
- self.assertContains(response, 'This field is required', 3)
- self.assertEqual(response.template.name, "Invalid POST Template")
+ self.assertContains(response, 'This field is required.', 3)
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, "Invalid POST Template")
+
+ self.assertFormError(response, 'form', 'email', 'This field is required.')
+ self.assertFormError(response, 'form', 'single', 'This field is required.')
+ self.assertFormError(response, 'form', 'multi', 'This field is required.')
def test_form_error(self):
"POST erroneous data to a form"
@@ -111,7 +127,57 @@ def test_form_error(self):
}
response = self.client.post('/test_client/form_view/', post_data)
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.template.name, "Invalid POST Template")
+ self.assertTemplateUsed(response, "Invalid POST Template")
+
+ self.assertFormError(response, 'form', 'email', 'Enter a valid e-mail address.')
+
+ def test_valid_form_with_template(self):
+ "POST valid data to a form using multiple templates"
+ post_data = {
+ 'text': 'Hello World',
+ 'email': 'foo@example.com',
+ 'value': 37,
+ 'single': 'b',
+ 'multi': ('b','c','e')
+ }
+ response = self.client.post('/test_client/form_view_with_template/', post_data)
+ self.assertContains(response, 'POST data OK')
+ self.assertTemplateUsed(response, "form_view.html")
+ self.assertTemplateUsed(response, 'base.html')
+ self.assertTemplateNotUsed(response, "Valid POST Template")
+
+ def test_incomplete_data_form_with_template(self):
+ "POST incomplete data to a form using multiple templates"
+ post_data = {
+ 'text': 'Hello World',
+ 'value': 37
+ }
+ response = self.client.post('/test_client/form_view_with_template/', post_data)
+ self.assertContains(response, 'POST data has errors')
+ self.assertTemplateUsed(response, 'form_view.html')
+ self.assertTemplateUsed(response, 'base.html')
+ self.assertTemplateNotUsed(response, "Invalid POST Template")
+
+ self.assertFormError(response, 'form', 'email', 'This field is required.')
+ self.assertFormError(response, 'form', 'single', 'This field is required.')
+ self.assertFormError(response, 'form', 'multi', 'This field is required.')
+
+ def test_form_error_with_template(self):
+ "POST erroneous data to a form using multiple templates"
+ post_data = {
+ 'text': 'Hello World',
+ 'email': 'not an email address',
+ 'value': 37,
+ 'single': 'b',
+ 'multi': ('b','c','e')
+ }
+ response = self.client.post('/test_client/form_view_with_template/', post_data)
+ self.assertContains(response, 'POST data has errors')
+ self.assertTemplateUsed(response, "form_view.html")
+ self.assertTemplateUsed(response, 'base.html')
+ self.assertTemplateNotUsed(response, "Invalid POST Template")
+
+ self.assertFormError(response, 'form', 'email', 'Enter a valid e-mail address.')
def test_unknown_page(self):
"GET an invalid URL"
View
2  tests/modeltests/test_client/urls.py
@@ -2,11 +2,13 @@
import views
urlpatterns = patterns('',
+ (r'^no_template_view/$', views.no_template_view),
(r'^get_view/$', views.get_view),
(r'^post_view/$', views.post_view),
(r'^raw_post_view/$', views.raw_post_view),
(r'^redirect_view/$', views.redirect_view),
(r'^form_view/$', views.form_view),
+ (r'^form_view_with_template/$', views.form_view_with_template),
(r'^login_protected_view/$', views.login_protected_view),
(r'^session_view/$', views.session_view),
(r'^broken_view/$', views.broken_view)
View
24 tests/modeltests/test_client/views.py
@@ -4,6 +4,11 @@
from django.contrib.auth.decorators import login_required
from django.newforms.forms import Form
from django.newforms import fields
+from django.shortcuts import render_to_response
+
+def no_template_view(request):
+ "A simple view that expects a GET request, and returns a rendered template"
+ return HttpResponse("No template used")
def get_view(request):
"A simple view that expects a GET request, and returns a rendered template"
@@ -79,6 +84,25 @@ def form_view(request):
c = Context({'form': form})
return HttpResponse(t.render(c))
+
+def form_view_with_template(request):
+ "A view that tests a simple form"
+ if request.method == 'POST':
+ form = TestForm(request.POST)
+ if form.is_valid():
+ message = 'POST data OK'
+ else:
+ message = 'POST data has errors'
+ else:
+ form = TestForm()
+ message = 'GET form page'
+ return render_to_response('form_view.html',
+ {
+ 'form': form,
+ 'message': message
+ }
+ )
+
def login_protected_view(request):
"A simple view that is login protected."
View
8 tests/templates/base.html
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<h1>Django Internal Tests: {% block title %}{% endblock %}</h1>
+{% block content %}
+{% endblock %}
+</body>
+</html>
View
15 tests/templates/form_view.html
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+{% block title %}Submit data{% endblock %}
+{% block content %}
+<h1>{{ message }}</h1>
+<form method='post' action='.'>
+{% if form.errors %}
+<p class='warning'>Please correct the errors below:</p>
+{% endif %}
+<ul class='form'>
+{{ form }}
+<li><input type='submit' value='Submit'></li>
+</ul>
+</form>
+
+{% endblock %}
View
10 tests/templates/login.html
@@ -1,7 +1,6 @@
-<html>
-<head></head>
-<body>
-<h1>Django Internal Tests: Login</h1>
+{% extends "base.html" %}
+{% block title %}Login{% endblock %}
+{% block content %}
{% if form.has_errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
@@ -15,5 +14,4 @@
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
-</body>
-</html>
+{% endblock %}
Please sign in to comment.
Something went wrong with that request. Please try again.