David Talbot

Django - testing model methods

Fri 25 April 2014 / djangotesting

I recently stumbled upon a "gotcha" which may help someone else testing Django model methods.

An overview: I recently found myself in a situation where I needed to ensure that the slug field on a model was unique.

A simplification of the model is as follows:

from django.db import models

class Foo(models.Model):  
name = models.CharField(max\_length=100)  
slug = models.SlugField(unique=True)  

In terms of how to test this change to the model, my initial thoughts were that things should be fairly simple: create an object with a specific slug and then create another object with the same slug, expecting an IntegrityError to be raised. As such, my approach was to write the following:

from django.db import IntegrityError  
from django.test import TestCase  
from .models import Foo

class FooModelTest(TestCase):

    def test_unique_slug(self):  
    """A slug should be unique.  
    """  
    f1 = Foo(name="Foo1", slug="foo1")  
    f1.save()  
    f2 = Foo(name="Foo2", slug="foo1")  
    self.assertRaises(IntegrityError, f2.save())  

However, rather than checking that the IntegrityError was being raised was being raised, the IntegrityError was called before the test could run.

What had happened was that, rather than passing the save method itself to self.assertRaises I was calling save() directly: an IntegrityError was being raised before the test had even been run, rather than having the test itself check the save method in the assertion.

To fix this, I removed the parentheses from f2.save() i.e.

...  
self.assertRaises(IntegrityError, f2.save)  

then everything works exactly as expected.