Today I ran across an issue while debugging Django tests. As stated in the docs, all model changes in a TestCase that are done during the test are reverted between the tests. This creates a nice and useful isolation of the different tests. Each time a test runs, the database looks just the way it was after the syncdb.
These test run fine, even though two users with the same PK are created, because Django handles test isolation. But things behave differently when using the setUpClass classmethod. I used setUpClass instead of setUp because there are certain models that I just want to create once for all the tests in a test case. It would be an unnecessary performance loss if those model instances were created and then rolled back for each test method. And less DRY.
The problem is, model changes that are done in setUpClass aren't rolled back between the test cases.
> from django.test import TestCase
> from apps.front import models
>
> class Test1(TestCase):
> @classmethod
> def setUpClass(cls):
> models.User.objects.create(username='spamham')
>
> def test(self):
> pass
>
> class Test2(TestCase):
> @classmethod
> def setUpClass(cls):
> models.User.objects.create(username='spamham')
>
> def test(self):
> pass
This fails with an IntegrityError due to a violation of the front_user_username_key unique constraint, because the User object from the first test wasn't removed.
Is this a design decision? Or a technical limitation? (I realize that the use of a setup classmethod could cause issues with parallelization, but those issues could be addressed in the test runner.)
And in the meantime, is there a better solution than to put all the common setup code in the setUp method?
Note that I don't want to use fixtures for this. Fixtures are not a good way to create test data, as they're very static and need to be updated with the code. This also makes them error-prone. Instead I'm using Model Mommy (
https://github.com/vandersonmota/model_mommy), a model factory library for Django. Another good alternative would be Factory Boy. These factories are also the reasons why I don't want to do manual cleanup in tearDownClass: First of all the model factory also creates related models that are needed to satisfy some foreign key constraints. I don't have references to all those model instances. And the second reason is that I think the database cleanup is something that Django should handle, not me.
Danilo