13

I'm trying to run the following Django unittest:

class MyModelTests(TestCase):
    def test_failed_duplicate(self):
        m = MyModel.objects.create(a='a', b='a')
        with self.assertRaises(IntegrityError):
            MyModel.objects.create(a='a', b='b')
        with self.assertRaises(IntegrityError):
            MyModel.objects.create(a='a', b='c')
        with self.assertRaises(IntegrityError):
            MyModel.objects.create(a='a', b='d')

There are several tests that all should fail due to violating a uniqueness constraint on field a. (I've obfuscated the assertions a bit, but they all test different values of a that should fail.)

However, when running I get:

Traceback (most recent call last):
  File "...", line 21, in test_failed_duplicate
    MyModel.objects.create(a='a', b='c')
TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

What am I missing?

1 Answer 1

30

The reason you're seeing this is that:

  1. For performance reasons, TestCase tests run inside a transaction.
  2. The raising of an IntegrityError will spoil the current transaction (more precisely, the current atomic block), regardless of whether or not it is caught.

So, in your code, the first assertRaises works correctly, but because an IntegrityError was raised the transaction becomes spoiled. When you try to access the database with the next create() you get the TransactionManagementError. See this ticket for more information.

There are two possible solutions:

  1. Inherit from TransactionTestCase instead of TestCase. This uses table truncation instead of transactions to reset the databse, so you won't have this problem.
  2. Run each of your create() tests inside a new atomic block. You can see an example in the ticket, and a broader description in the docs.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.