Django: Change Logging Level During Tests

So you’ve been a good developer and using the logger instead of print statements. You can change the log level and make DEBUG statements appear or disappear. How to do this when you are running tests? Just add something like this to

import logging

Django Testing and Postgresql Flush

Just to be clear on terminology, the following code has one test class with two tests:

from django.test import TestCase

class MyTest(TestCase):
    def test_some_stuff(self):
        print 'Some test code'
    def test_some_other_stuff(self):
        print 'Some other test code'

The test database is supposed to be flushed between tests. You can run the tests individually like this:

python test my_app.MyTest.test_some_stuff
python test my_app.MyTest.test_some_other_stuff

What does it mean when the tests work when they are run individually, but they fail when run together as:

python test my_app.MyTest

One possibility is that the database is not really being flushed. In fact this is kind of true. It turns out that although the database is flushed, the auto-indexing is not reset. So if you are silly enough to base an assertion on an instance ID., things might not work as expected.

Of course you would never be that silly. But a lesser programmer might do it this way. Suppose junk contains a foreign key to stuff. The programmer might not care which junk is used. He might write:

junk = Junk.objects.get(id=1)   # Just grab the first one
stuff = Stuff(junk=junk)

The problem occurs when this test comes after another test that makes junk. Because auto-indexing did not reset, there may not be a junk record with id=1.

Django-Webtest Tips and Gotcha’s

Based on lots of comments and other stuff on the “Internets”, I have started using Django-Webtest. Webtest inherits from Django TestCase. It allows you to interact with forms more like the user does. For example you can select an option from an HTML Select tag.  I am still trying to decide if this extra functionality is worth having to deal with another layer of documentation. Especially since that layer is sparse.

Anyway, these are my notes for getting things done with Webtest. This post is not meant to be a tutorial or replace the docs. Rather its just stuff I have found useful and hard to find in the docs.

Viewing the Page in a Browser

Let’s say you are testing a form and things are not going as planned. Sometimes the easiest way to solve the problem is to view the page. Here is how:

form ='login')).form
form['email'] =
form['password'] = self.test_password
response = form.submit().follow()

The last line is where the magic is.

Finding Stuff on the Page

Webtest provides the Beautiful Soup parsed HTML in the .html attribute of a response. One way this is useful is to assert things about the content of a page. For example:

response ='my_url', args=[]), user='jim')
delete_button = response.html.find('button', id='delete_button')

Checking the URL After Redirect

Sure, you can use status code. But what if you want to know where you were redirected? Use this Django assertion:

response = form.submit()
self.assertRedirects(response, reverse('my_named_url'))
response =, user='test')  # do the redirect

Occasionally this does not work. For some reason, the port gets inserted in the response.url, while its not in reverse(). I have seen this problem occur with some assertRedirects and not others in the same test method. Here is one way to get around this:

from urlparse import urlparse

def my_assertRedirects(self, response, expected_url):
    parts = urlparse(response.url)
    self.assertEqual(parts.path, expected_url)

Handling MultipleChoiceField

I am using django-crispy forms. When I make an InlineCheckBoxes of a Django MultipleChoiceField, I end up with several HTML checkbox tags with the same name. Hence the usual method for assigning a value does not work. Here is something that does work:

form.set('my_checkbox_name', True, index=1)

where the index keyword specifies which checkbox with name “my_checkbox_name”.

Handling Form Errors

One way to handle form errors is to look at the response_status. For most of my forms, a status of 200 is returned when there is an error. While a 302 (redirect) is returned when there are no errors. Although this works, it feels like a pretty blunt instrument for handling form errors.

One interesting fact about WebTest is it inherits from Django TestCase. What his means is that some of the functionality of TestCase still works. For example, you can submit a form using the post method of the Django Client class.

For error handling, you can still use:

response = form.submit('save')
self.assertFormError(response, 'form', 'user_type', u'This field is required.')

or for non field errors:

response = response.form.submit('save')
self.assertFormError(response, 'form', None, ['an error message', 'another error message'])

Note that the word form is a string. It is the name of the form in the context dict that you send to render. Here are the docs on assertFormError.

What if you are getting a form error, but you are not sure what error it is? The place to start looking is in the response.context list.

Form Submit

Lets say you have a form that redirects after it is successfully submitted. If you submit it like this:

response = form.submit('save')
print response.status
>>>302 FOUND

In the browser, you will see a blank page.  What is going on here is Webtest did not automatically go to the page you are redirecting to. To have it go to that page, do this:

response = form.submit('save').follow()

ModelForm Initial Values

This one is baffling. If you pass initial values to a ModelForm using the initial keyword, they do not appear in the form! How do I know this? If I run the code outside of testing, they appear. If I run the code in testing and do showbrowser() they are not there. If I set break points during testing, I can see that the “initial” keyword has the correct values.

HTTP Forbidden (403)

With the systems I design, it is often necessary to limit access to views based on attributes of the user. Thus a big part of testing is making sure users cannot view things they are not allowed to view.

You would think this would be a simple test:

response ='my_view'))
self.assertEqual(response.status_code, 403)

But if you do that you get an error:

AppError: Bad response: 403 FORBIDDEN

Instead try this:

response ='my_view'), status=403)

If the response status is not 403, an error will be raised, which is exactly what you want.

Clicking a Link

If there is a link on your page (<a></a>) the webtest response object has a method called “click” which lets you click on the link. Seems easy enough. You can send regular expression patterns or strings to select the link you need.

The gottcha is when the uses “onclick” as its action. When the method is searching for the link, it also checks to see what the tags href attribute is. If there is no href attribute, then the link is skipped even if it matches the linkid.

In a way this makes sense because the click method ends with a call to the goto method. In any case, WebTest does not run javascript. Guess I need to use selenium for this.

Use the Verbose Keyword

Several methods accept the keyword “verbose”. Use it to speed up debugging.


The good news is you can inspect session variables by looking at:

The bad news is I cannot figure out how to set a session variable inside a test. It seems that writing to does not work. WebTest uses a special backend to handle auth. It seems that is not connected to the normal session processing. If you know how to do this, let me know!

Ugh… this worse than I thought. For some mysterious reason, the session vars are not carrying over between views. I am solving this by switching to Django TestCase.