I’ve recently developed some Django sites where I was able to ensure all features were thoroughly tested. I learnt a lot about writing maintainable tests, and I’d like to share with you.

## A basic view

When you’re starting out developing your site, your views will be simple. Your index view probably looks something like this:

Now, what properties do we want this view to have? We want it to render without errors. Here’s a test:

Hey presto, your index view is tested!

When thinking about testing, you should ask yourself: ‘what properties do I want this view to have?’ In this case, we just want to check the view renders. This helps us catch any silly errors (such as incorrect template names) that may occur.

What’s nice about this test is that no legitimate refactoring will cause the test to fail. Django provides many specific assertion methods, such as assertTemplateUsed and assertHTMLEqual. These have their uses, but they limit you. If you use assertTemplateUsed and refactor your templates, you will have to update your tests. Grrr.

## Testing a form

Suppose we’re writing a form for users to sign up. Here’s what our view looks like:

What are we interested in here? We want the page to load, we want users to be able to register, and we want form validation. I’ve written django-test-mixins to provide these assertions.

We don’t want tests to become a burden in later development. There are two things we’ve done to ensure our tests are future-friendly.

Firstly, we’re careful to only make an assertion about the user we’re interested in. We don’t want to assume how many users exist in the system. Websites often start off with a single admin user, but we shouldn’t bake that assumption into our tests. This assertion:

is worse, because we are making assumptions about the state of our database.

Secondly, we’ve factored out the form parameters. The exact number of form parameters often changes as features are added. It’s a pain to change lots of tests because you’ve added one field to form, so keep it DRY.

## Testing protected views

Finally, let’s look at a more complex view.

We have authentication here and we need some existing models to test the view.

We need a blog post to test this view, and we could explicitly create one. This is tedious, and milkman can do this for us.

Finally, we want an easy way of creating users to test that our view applies authentication correctly.

We factor out user creation so we have a single place in our tests that provides reusable methods for creating users according to th eneeds of our site.

We want to test that our view validates users correctly and that it modifies blog posts correctly. Since each test should only verify one thing, we will write three tests.

This is how I write tests with Django. Don’t worry about writing perfect tests, having tests at all is a huge boon. Once you have them, don’t be afraid to keep iterating on them. Always seek out ways to make testing easier next time.