Testing several IntegrityErrors in the same Django unittest test case
django, django-models, testing, unit-testing
Solution
The reason you're seeing this is that:
- For performance reasons, `TestCase` tests run inside a transaction.
- 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:
- Inherit from `TransactionTestCase` instead of `TestCase`. This uses table truncation instead of transactions to reset the databse, so you won't have this problem.
- 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.
Problem
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?