Opened 6 years ago

Closed 5 years ago

Last modified 4 years ago

#12087 closed (wontfix)

Django "TransactionTestCase" isn't

Reported by: brandon Owned by: nobody
Component: Testing framework Version: 1.1
Severity: Keywords:
Cc: jonathan+django@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: yes Patch needs improvement: no
Easy pickings: UI/UX:

Description

The Django TransactionTestCase fails to roll back the current database transaction at each test's conclusion, which can leave the current database connection in an unusable state and thus break test isolation. When Django is using PostgreSQL, and a test deliberately tries violating a database invariant (like inserting an illegal value, or a non-existent primary key) and receives a PostgreSQL runtime error, then all subsequent tests in that test class error out with the failure:

Traceback (most recent call last):
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/test/testcases.py", line 242, in __call__
    self._pre_setup()
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/test/testcases.py", line 217, in _pre_setup
    self._fixture_setup()
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/test/testcases.py", line 222, in _fixture_setup
    call_command('flush', verbosity=0, interactive=False)
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/core/management/__init__.py", line 166, in call_command
    return klass.execute(*args, **defaults)
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/core/management/base.py", line 222, in execute
    output = self.handle(*args, **options)
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/core/management/base.py", line 351, in handle
    return self.handle_noargs(**options)
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/core/management/commands/flush.py", line 31, in handle_noargs
    sql_list = sql_flush(self.style, only_django=True)
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/core/management/sql.py", line 128, in sql_flush
    tables = connection.introspection.django_table_names(only_existing=True)
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/db/backends/__init__.py", line 510, in django_table_names
    tables = [t for t in tables if self.table_name_converter(t) in self.table_names()]
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/db/backends/__init__.py", line 491, in table_names
    return self.get_table_list(cursor)
  File "/home/brandon/django/v/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/db/backends/postgresql/introspection.py", line 30, in get_table_list
    AND pg_catalog.pg_table_is_visible(c.oid)""")
InternalError: current transaction is aborted, commands ignored until end of transaction block

The correction for this is very simple: the _fixture_teardown() method in django.test.testcases.TransactionTestCase needs its code changed from a do-nothing "pass" statement to something more effective:

    def _fixture_teardown(self):
        transaction.rollback()

With this small change, test isolation is correctly achieved, and the rest of the test cases in the TransactionTestCase class can succeed and fail on their own rather than all dying with the error shown above.

Change History (5)

comment:1 Changed 6 years ago by jonathan

  • Cc jonathan+django@… added
  • Component changed from Testing framework to Database layer (models, ORM)
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

This ticket is related to: #10813, #12028.

Need global fix ?

comment:2 Changed 5 years ago by russellm

  • Component changed from Database layer (models, ORM) to Testing framework
  • Has patch set
  • milestone set to 1.2
  • Needs tests set
  • Triage Stage changed from Unreviewed to Accepted

comment:3 Changed 5 years ago by ericholscher

It would be useful to have a test case showing this behavior in action. The fix sounds simple enough.

comment:4 Changed 5 years ago by jacob

  • Resolution set to wontfix
  • Status changed from new to closed

To my eyes, TransactionTestCase does exactly what the documentation says it does: force you to handle transactions yourself. This means that you need to do the commit/rollback handling yourself.

Remember you can always easily writing your own TestCase (or TransactionTestCase subclass to handle this stuff however your app wants. Django provides two common options; less common ones can -- and should -- be confined to your own projects.

[Yes, TransactionTestCase could have been named better. Water under the bridge now, though.]

comment:5 Changed 4 years ago by jacob

  • milestone 1.2 deleted

Milestone 1.2 deleted

Note: See TracTickets for help on using tickets.
Back to Top