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.)

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

-- 
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.


Reply via email to