On Mon, Apr 29, 2013 at 4:08 AM, Danilo Bargen <[email protected]> wrote:
> Hi all > > 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. > > > from django.test import TestCase > > from apps.front import models > > > > class Test1(TestCase): > > def setUp(self): > > models.User.objects.create(username='spamham') > > > > def test(self): > > pass > > > > class Test2(TestCase): > > def setUp(self): > > models.User.objects.create(username='spamham') > > > > def test(self): > > pass > > 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.) > Neither really. It's an artefact of the history of Django's test framework. The test framework was written almost 7 years ago, predating unittest2 by several years. setUpClass was introduced by unittest2. As a result, the infrastructure that resets tests after each setUp/tearDown pair hasn't been modified to include setUpClass/tearDownClass as well. I haven't looked at the problem in detail to establish if there is a fundamental technical limitation preventing this; but off the top of my head, I can think of a few complications that might pose difficulty. In particular, the transaction rollback approach used to speed up fixture loading won't adapt well to having two different 'setup' routines. > And in the meantime, is there a better solution than to put all the common > setup code in the setUp method? > Unfortuntately not. > 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. > If you want to avoid fixtures, Factory Boy would be my suggestion; I haven't used Model Mommy myself, but it looks to be in much the same vein. Yours, Russ Magee %-) -- You received this message because you are subscribed to the Google Groups "Django developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/django-developers?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
