Added assertFormError, assertTemplateUsed and assertTemplateNotUsed for use during unit testing.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5156 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
64adc41377
commit
f073797f4c
|
@ -77,4 +77,62 @@ class TestCase(unittest.TestCase):
|
||||||
real_count = response.content.count(text)
|
real_count = response.content.count(text)
|
||||||
self.assertEqual(real_count, count,
|
self.assertEqual(real_count, count,
|
||||||
"Could only find %d of %d instances of '%s' in response" % (real_count, count, text))
|
"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)
|
||||||
|
|
|
@ -462,15 +462,36 @@ Normal Python unit tests have a wide range of assertions, such as
|
||||||
``django.TestCase`` adds to these, providing some assertions
|
``django.TestCase`` adds to these, providing some assertions
|
||||||
that can be useful in testing the behavior of web sites.
|
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)``
|
``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``
|
(i.e., the HTTP status code was 200), and that ``text`` occurs ``count``
|
||||||
times in the content of the response.
|
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
|
Running tests
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,13 @@ class ClientTest(TestCase):
|
||||||
self.assertEqual(response.context['var'], 42)
|
self.assertEqual(response.context['var'], 42)
|
||||||
self.assertEqual(response.template.name, 'GET Template')
|
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):
|
def test_get_post_view(self):
|
||||||
"GET a view that normally expects POSTs"
|
"GET a view that normally expects POSTs"
|
||||||
response = self.client.get('/test_client/post_view/', {})
|
response = self.client.get('/test_client/post_view/', {})
|
||||||
|
@ -40,6 +47,8 @@ class ClientTest(TestCase):
|
||||||
# Check some response details
|
# Check some response details
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.template.name, 'Empty GET Template')
|
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):
|
def test_empty_post(self):
|
||||||
"POST an empty dictionary to a view"
|
"POST an empty dictionary to a view"
|
||||||
|
@ -48,6 +57,8 @@ class ClientTest(TestCase):
|
||||||
# Check some response details
|
# Check some response details
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.template.name, 'Empty POST Template')
|
self.assertEqual(response.template.name, 'Empty POST Template')
|
||||||
|
self.assertTemplateNotUsed(response, 'Empty GET Template')
|
||||||
|
self.assertTemplateUsed(response, 'Empty POST Template')
|
||||||
|
|
||||||
def test_post(self):
|
def test_post(self):
|
||||||
"POST some data to a view"
|
"POST some data to a view"
|
||||||
|
@ -88,7 +99,7 @@ class ClientTest(TestCase):
|
||||||
}
|
}
|
||||||
response = self.client.post('/test_client/form_view/', post_data)
|
response = self.client.post('/test_client/form_view/', post_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
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):
|
def test_incomplete_data_form(self):
|
||||||
"POST incomplete data to a form"
|
"POST incomplete data to a form"
|
||||||
|
@ -97,8 +108,13 @@ class ClientTest(TestCase):
|
||||||
'value': 37
|
'value': 37
|
||||||
}
|
}
|
||||||
response = self.client.post('/test_client/form_view/', post_data)
|
response = self.client.post('/test_client/form_view/', post_data)
|
||||||
self.assertContains(response, 'This field is required', 3)
|
self.assertContains(response, 'This field is required.', 3)
|
||||||
self.assertEqual(response.template.name, "Invalid POST Template")
|
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):
|
def test_form_error(self):
|
||||||
"POST erroneous data to a form"
|
"POST erroneous data to a form"
|
||||||
|
@ -111,7 +127,57 @@ class ClientTest(TestCase):
|
||||||
}
|
}
|
||||||
response = self.client.post('/test_client/form_view/', post_data)
|
response = self.client.post('/test_client/form_view/', post_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
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):
|
def test_unknown_page(self):
|
||||||
"GET an invalid URL"
|
"GET an invalid URL"
|
||||||
|
|
|
@ -2,11 +2,13 @@ from django.conf.urls.defaults import *
|
||||||
import views
|
import views
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
|
(r'^no_template_view/$', views.no_template_view),
|
||||||
(r'^get_view/$', views.get_view),
|
(r'^get_view/$', views.get_view),
|
||||||
(r'^post_view/$', views.post_view),
|
(r'^post_view/$', views.post_view),
|
||||||
(r'^raw_post_view/$', views.raw_post_view),
|
(r'^raw_post_view/$', views.raw_post_view),
|
||||||
(r'^redirect_view/$', views.redirect_view),
|
(r'^redirect_view/$', views.redirect_view),
|
||||||
(r'^form_view/$', views.form_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'^login_protected_view/$', views.login_protected_view),
|
||||||
(r'^session_view/$', views.session_view),
|
(r'^session_view/$', views.session_view),
|
||||||
(r'^broken_view/$', views.broken_view)
|
(r'^broken_view/$', views.broken_view)
|
||||||
|
|
|
@ -4,6 +4,11 @@ from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.newforms.forms import Form
|
from django.newforms.forms import Form
|
||||||
from django.newforms import fields
|
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):
|
def get_view(request):
|
||||||
"A simple view that expects a GET request, and returns a rendered template"
|
"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})
|
c = Context({'form': form})
|
||||||
|
|
||||||
return HttpResponse(t.render(c))
|
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):
|
def login_protected_view(request):
|
||||||
"A simple view that is login protected."
|
"A simple view that is login protected."
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body>
|
||||||
|
<h1>Django Internal Tests: {% block title %}{% endblock %}</h1>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</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 %}
|
|
@ -1,7 +1,6 @@
|
||||||
<html>
|
{% extends "base.html" %}
|
||||||
<head></head>
|
{% block title %}Login{% endblock %}
|
||||||
<body>
|
{% block content %}
|
||||||
<h1>Django Internal Tests: Login</h1>
|
|
||||||
{% if form.has_errors %}
|
{% if form.has_errors %}
|
||||||
<p>Your username and password didn't match. Please try again.</p>
|
<p>Your username and password didn't match. Please try again.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -15,5 +14,4 @@
|
||||||
<input type="submit" value="login" />
|
<input type="submit" value="login" />
|
||||||
<input type="hidden" name="next" value="{{ next }}" />
|
<input type="hidden" name="next" value="{{ next }}" />
|
||||||
</form>
|
</form>
|
||||||
</body>
|
{% endblock %}
|
||||||
</html>
|
|
Loading…
Reference in New Issue