@Crast's answer was good, but I think incomplete. The code I use in my unit tests for determining if an object is in the database is as follows. Below it, I will explain why I think it is superior to checking if obj.pk is None
.
My solution
from django.test import TestCase
class TestCase(TestCase):
def assertInDB(self, obj, msg=None):
"""Test for obj's presence in the database."""
fullmsg = "Object %r unexpectedly not found in the database" % obj
fullmsg += ": " + msg if msg else ""
try:
type(obj).objects.get(pk=obj.pk)
except obj.DoesNotExist:
self.fail(fullmsg)
def assertNotInDB(self, obj, msg=None):
"""Test for obj's absence from the database."""
fullmsg = "Object %r unexpectedly found in the database" % obj
fullmsg += ": " + msg if msg else ""
try:
type(obj).objects.get(pk=obj.pk)
except obj.DoesNotExist:
return
else:
self.fail(fullmsg)
Notes: Use the above code with care if you use custom managers on your models name something other than objects
. (I'm sure there's a way to get Django to tell you what the default manager is.) Further, I know that /assert(Not)?InDB/
are not a PEP 8 method names, but I used the style the rest of the unittest
package used.
Justification
The reason I think assertInDB(obj)
is better than assertIsNotNone(obj.pk)
is because of the following case. Suppose you have the following model.
from django.db import models
class Node(models.Model):
next = models.OneToOneField('self', null=True, related_name='prev')
Node
models a doubly linked list: you can attach arbitrary data to each node using foreign keys and the tail is the Node
obj such that obj.next is None
. By default, Django adds the SQL constraint ON DELETE CASCADE
to the primary key of Node
. Now, suppose you have a list
nodes of length n such that nodes[i].next == nodes[i + 1]
for i in [0, n - 1). Suppose you call nodes[0].delete()
. In my tests on Django 1.5.1 on Python 3.3, I found that nodes[i].pk is not None
for i in [1, n) and only nodes[0].pk is None
. However, my /assert(Not)?InDB/
methods above correctly detected that nodes[i]
for i in [1, n) had indeed been deleted.