I would like to share with you an issue we encounter while moving from
sqlite to postgres with heavily use of Django testing.
We have Django app with ~700 tests. Most of them accessing database. We
recently migrated the database from sqlite to postgres.
Many of our tests were written in a way that compares actual pk’s
(hard-coded pks or just file/json comparisons) . Since Django testing on
sqlite (testcases.TestCase class) creates in-memory database (which is
being reseted every unit test by default), we never had a problem with it.
However, Django TestCase on postgres create completely another test db
which preserves the pk sequences between different tests. And since many of
our tests were written in a way that compares actual pk’s they all start
fail - depends on the exact tests execution order.
Even tests which expect some pk and are were not failed yet, can
potentially failed in the future - depends on adding/editing other tests
which may change the db sequence
We consider the following solutions:
1. Move to TransactionTestCase (instead of TestCase) and use
“reset_sequences = True” flag. Cons: TransactionTestCase reduces
performance dramatically (~4 times longer in some of the tests)
2. Refactor all failed tests: remove all hard-coded references to the
pk. Cons: Require much Dev effort (we had more then 70 such tests)
3. Route the database in settings.py such it will use sqlite instead of
postgres when running tests. Cons: It will not actually test the real
scenarios - not an option
4. Combine reset_sequences flag with TestCase in our own version to
TestCase: OurTestCase class and make everything to inherit from it. This is
the option we finally decided of. See below.
from django.test import TestCase, testcases
class OurTestCase(TestCase):
reset_sequences = True
def _fixture_setup(self):
for db_name in self._databases_names(include_mirrors=False):
if self.reset_sequences:
self._reset_sequences(db_name)
if self.fixtures:
call_command('loaddata', *self.fixtures, **{'verbosity': 0,
'database': db_name})
if not testcases.connections_support_transactions():
self.setUpTestData()
return super(TestCase, self)._fixture_setup()
self.atomics = self._enter_atomics()
Another problem of these kind of tests is the default ordering assumption
of Django which changes significantly between postgres and sqlite when
testing.
Therefore, models included in such tests must have a hint for Django
regarding the default ordering retrieval.
Our solution was to make all models inherit from DexterModelDefaultOrder
(below)
class DexterModelDefaultOrder(models.Model):
class Meta:
abstract = True
ordering = ['id']
I hope it (will) help someone
--
You received this message because you are subscribed to the Google Groups
"Django users" 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 https://groups.google.com/group/django-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-users/ffcd3cc9-c3be-44ba-9665-a4ded5fed492%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.