Django Unit Tests and Transactions
Coming to automated testing in Django from the Zope and Plone world, I was pleased to find full support for all the testing machinery that I've become used to: regular Python unit tests, and doctests. Of course, these being unit tests, they don't do any 'framework' management out of the box.
Unit tests are supposed to test your code, and just your code. However, once you're in a framework environment (be that Zope and Plone, Django, or anything else) then testing how your code integrates with that framework is vital. Zope and Plone provide unittest.TestCase subclasses (ZopeTestCase and PloneTestCase respectively) which provide a lot of scaffolding for you to be able to run integration tests. Part of that scaffolding is automatic transaction management. This hooks into Zope's transaction API to roll back the transaction after each test runs.
I wanted to do something similar for my Django test cases; I was finding 'state pollution' between my unit test runs, since data created by one test method isn't automatically cleaned out.
Django's transaction handling is much simpler than Zope's: it cares only about the one database transaction that the current request has, and only if the transaction support middleware is installed. This means that we can pretty easily crib the code from that middleware and use it in a test case base class:
from django.db import transaction
class TransactionalTestCase(unittest.TestCase):
def setUp(self):
super(TransactionalTestCase, self).setUp()
transaction.enter_transaction_management()
transaction.managed(True)
def tearDown(self):
super(TransactionalTestCase, self).tearDown()
if transaction.is_dirty():
transaction.rollback()
transaction.leave_transaction_management()
UPDATE: Fixed an error in the call to the base class' tearDown() method, which caused open transactions to hang around and (among other things) prevented the test database being cleanly dropped at the end of the test run.
After this, you can simply derive your test fixture classes from TransactionalTestCase, and make sure that you call the base setUp() and tearDown() methods if you do need to override them to perform your own setup and teardown.
My next spare time (hah!) project will be to integrate Django's transaction management into repoze.tm (which is Zope's transaction management suitably WSGI-fied). This would let a Django application participate in transactions with other transaction-aware components, making integration at the WSGI layer much more straightforward.
Comments
1 Osvaldo Santana Neto says...
def tearDown(self): - super(TransactionalTestCase, self).setUp() + super(TransactionalTestCase, self).tearDown()
Posted at 12:59 a.m. on July 2, 2008
2 Remco Wendt says...
Hi Dan,
I think you're better off using Django's testcase (django.test.TestCase) which does exactly this and more.
Remco
Posted at 8:48 a.m. on July 4, 2008
3 Dan Fairs says...
Yep - spot on! I seem to have a habit of only finding out about things after I've written something similar. Must get to know Google better...
Thanks for the comment.
Posted at 10:21 p.m. on July 28, 2008
4 Dan Fairs says...
Good spot - fixed.
Posted at 10:21 p.m. on July 28, 2008
5 Ben says...
It's probably worth a mentioning that django's transaction handling doesn't actually create a transaction (with a BEGIN) when you do enter_transaction_management. Postgres is the only db that does anything and it just calls set_isolation_level on the underlying dbapi connection. Ben
Posted at 11 a.m. on January 11, 2010
6 wholesale jerseys says...
our goal is to delight you with our distinctive collection of mindful ed hardy products while providing value and excellent service. Our goal is 100% customer satisfaction and we offer only 100% satisfacted service and ed hardy products. Please feel free to contact us at any time; we are committed to your 100% customer satisfaction. If you're looking for the best service and best selection, stay right where you are and continue shopping at here is your best online choice for the reasonable prices. So why not buy your ed hardy now, I am sure they we won’t let you down.
http://www.underjerseys.com/]wholesale nfl jerseys
Posted at 2:23 a.m. on July 31, 2010
7 ugg boots shoes says...
Ugg boots shoes <a href= http://www.uggsmall.com>Ugg boots shoes</a> five finger shoes <a href= http://www.acevibram.com/>five finger shoes</a> Uggs outlet <a href= http://www.uggsmall.com>Uggs outlet</a> cheap ugg boots <a href= http://www.uggsmall.com>cheap ugg boots</a> Ugg on sale <a href= http://www.uggsmall.com>Uggs on sale</a> Uggs australia <a href= http://www.uggsmall.com>Uggs australia</a> ugg bailey button boots <a href= http://www.uggsmall.com/ugg-bailey-button-boots-c-19.html... bailey button boots</a> ugg classic cardy boots <a href= http://www.uggsmall.com/ugg-classic-cardy-boots-c-2.html>ugg classic cardy boots</a> ugg nightfall boots <a href= http://www.uggsmall.com/ugg-nightfall-boots-c-4.html>ugg nightfall boots</a> ugg sundance ii boots <a href= http://www.uggsmall.com/ugg-sundance-ii-boots-c-5.html>ugg sundance ii boots</a> ugg classic mini boots <a href= http://www.uggsmall.com/ugg-classic-mini-boots-c-6.html>ugg classic mini boots</a> ugg kids boots <a href= http://www.uggsmall.com/ugg-kids-boots-c-20.html>ugg kids boots</a>
Posted at 3:55 a.m. on July 31, 2010