views:

480

answers:

2

Can somebody please explain to me how to properly test Postgres DB errors, particularly IntegrityError. For example i have next test:

class TestSlugs(TestCase):
    # This slug must be unique
    b = BookPublisher(slug=self.duplicate_slug)
    self.assertRaises(IntegrityError, b.save)

    #check if there's only one BookPublisher
    self.assertEquals(BookPublisher.objects.count(), 1)

Here it catches the IntegrityError but then all operations will fail, because that's how postgres works, ok. I see in docs that i can use transaction.rollback() but where: in test or in save() method?

Also, i don't like the idea of writing rollbacks by hand, why can't django just try to save, and if it fails - give me IntegrityError and let me continue to work.

I'm using django 1.1

+1  A: 

Hey dmishe,

not 100% sure that this is valid, but you could do:

def Save(self):
    transaction.commit()
    try:
        super(MyModel, self).save()
    except IntegrityError:
        transaction.rollback()
    else:
        transaction.commit()
Idan Gazit
thanks, i'll try that. But frankly speaking, this is ugly :)
Dmitry Shevchenko
+1  A: 

Don't alter the save() method, since you want it to propagate through under normal operations. You should catch the exception in your Test class and rollback there (note that since you're testing transactions you must subclass TransactionalTestCase instead of the normal TestCase).

Alex Gaynor
Ok thanks. So in live code, everything will be fine after catching IntegrityError? Or should i still rollback there explicitly?
Dmitry Shevchenko
You should avoid ever causing IntegrityError in your own code, and treat any SQL error as a bug. So you should check before trying some modification whether that modification will be sensible. If you find that the modification cannot be made, you can rollback and report the problem to the user. Or you can decide to skip the modification, or make a different modification instead.
Martin v. Löwis