New features in enhanced Django TestCase
For about a year I've been working on our Django Binder app. It was originally designed for use in intranet applications, but much of the code is useful in Django apps of all kinds.
I've just committed a bunch of improvements from my work on the iSchool project, which I'd like to highlight to anyone interested, partly as internal documentation.
Module-level features
- Removed the IntranetUser and IntranetGroup models, as they're not reusable, and the migrations, fixtures and management command. These models caused problems for people who added
binder
to theirINSTALLED_APPS
but didn't want to use the models, partly due to Django bug 19422.
Django database fields
You can import the binder.modelfields
module in your models.py
to access these field types.
- Add a database field type for IP address ranges with a CIDR network mask, including validation.
- Add a modified version of the ManyToManyField relation, which removes the annoying non-optional "help" text added by the Admin to all ManyToManyFields: Hold down "Control", or "Command" on a Mac, to select more than one. Even if the widget has been changed to checkboxes, where this instruction makes no sense.
Views
You can import the binder.views
module in your views.py
to access these mixins.
- Add a LoginRequiredMixin for class-based views, since I needed it several times and overriding the dispatch method, just to add a decorator, started to annoy me.
Monkey patches
These can be applied by importing the binder.monkeypatches
module, currently all-or-nothing.
- Patch the
Template.render
method to show the name of the template file where the rendering failed with an exception. Now you actually know where to look for the error. - Patch
URLNode.render
to check for using a variable name that doesn't exist, which probably means that you forgot to quote the name of the view you wanted to link to with{% url %}
. Otherwise it can be hard to work out where on the page the mistake is, without knowing what to look for. - Patch
URLNode.render
to check for using a variable name that points to a view that doesn't exist, and report the variable name and its value as well as the exception details, in case you used the wrong variable name in a{% url %}
, or it had a value that you didn't expect. - Patch
DateTimeField.get_prep_value
to report the field name containing the naive datetime, until Django bug 19560 gets fixed.
Django TestCase improvements
These can be used by making your test cases extend AptivateEnhancedTestCase
instead of Django's standard TestCase
.
- Fix the incorrect attempt to parse non-HTML responses from your views as HTML.
- If the response is a SimpleTemplateResponse, ensure that it's rendered before returning it to your test case, so that you can access
response.content
safely. - If the response has no
context
but it does have acontext_data
(not sure why, but this happened to me, on an error response I think), then copy the context data so that context assertions don't crash. - Improve error messages if login as a test user fails, e.g. because the test password doesn't match the one in the fixtures.
- Improve error message if non-dictionary passed to
assertInDict
. Otherwise it was easy to pass a list, and the error most confusing. - Split
absolute_url helper
intoabsolute_url_for_site
andabsolute_url_for_request
. There are two ways of building an absolute URL in the app: looking at the domain of the Site record in the database, and looking at the one being accessed by the current user. Before, the way of doing this was ambiguous, but now it's clear. This breaks backwards compatibility with tests using the old, ambiguous way. - Allow passing a message to the
extract_form
helper, which gets the form out of aresponse.context
, to be shown if the form is missing or the response has no context. - Report an error if
update_form_values
is called with values for fields that don't exist in the form. Just ignoring them leads to broken tests which are hard to debug. - Allow generating POST data with no value for a RadioSelect widget. When using this widget, it's possible for the user not to click on any of the radio buttons before submitting the form, i.e. not to make any selection, and we need to be able to test what happens in such cases.
- Improve the sanity check in
assert_followed_redirect
for calling the test client'sget
orpost
methods without passingfollow=True
. - Add an assertion that the response does not contain a form with errors, and if it does, fail with the validation errors in the message. This simplifies tests for views redirect somewhere else if the form is valid, or show the form again if not, such as the CreateView and UpdateView class-based views.
- Improve debugging of failed
reverse()
lookups. It's very unlikely that you passed in acallable
when you meant a non-callable or vice versa, so we only show URLs matching that type, which shortens the list of possibilities quite significantly.