7

Django’s TestCase class wraps each test in a transaction and rolls back that transaction after each test, in order to provide test isolation.

Apparently, however, only operations in the default database are within the scope of the transaction. I have a multiple database setup with a router that directs ORM calls on some models to a second database. This means that in the following example, test2 fails:

class MyTestCase(TestCase):

    def test1(self):
        # Let's say Foo model ORM calls are routed to a different DB
        foo = Foo.objects.create(...)
        assert foo.is_ok()

    def test2(self):
        assert not Foo.objects.exists()

The most immediate solution to this problem would be to override the tearDown method in MyTestCase and manually make sure to delete all Foo objects. But this is a bit annoying because it's sort of a hack and database sequences (e.g. autoincrement columns) won't be reset for example, only after the test suite is done and the database is destroyed.

Is there a way to properly fix this, making sure all database operations are by default made inside a transaction and rolled back at the end of each test?

[UPDATE]

Here's my router:

class FooRouter(object):

    def db_for_read(self, model, **hints):

        if model._meta.app_label == 'foo':
            return 'foo_db'

        return None

    def db_for_write(self, model, **hints):

        if model._meta.app_label == 'foo':
            return 'foo_db'

        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):

        if app_label == 'foo':
            return db == 'foo_db'

        return None
2
  • Hum, I don't know, I wouldn't think so. It's a pretty basic router. But anyway, I added the code, hope it helps. Commented Jul 12, 2016 at 6:51
  • test2 fails. Sorry I wasn't very explicit. Just updated the question to be clearer. Commented Jul 12, 2016 at 8:28

2 Answers 2

12

As multi_db is deprecated, you can now achieve test with multiple database with the new attribute databases

class YourTestCase(TestCase):
   databases = '__all__'

   def test_something(self):
       pass
Sign up to request clarification or add additional context in comments.

1 Comment

multi_db is deprecated from Django 2.2 version
1

In case you are not using DB Router, you can try to add multi_db = True to TestCase to call flush for all databases

class YourTestCase(TestCase):
   multi_db = True

   def test_something(self):
       pass

Django docs

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.