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?
The reason you're seeing this is that:
TestCase
tests run inside a transaction.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:
TransactionTestCase
instead of TestCase
. This uses table truncation instead of transactions to reset the databse, so you won't have this problem.create()
tests inside a new atomic block. You can see an example in the ticket, and a broader description in the docs.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With