Week 1: Tests, Transactions, and Tear Down

With our migrations fixed, we could now get on with the business of writing tests. Django uses Python's standard unittest package, which I'm well familiar with.1

We did a straightforward sort of TestCase, creating a User object and other instances of models needed by the code under test,2 we put that in a setUp method, and after we'd written a few of these, I asked shouldn't we write a tearDown method to clean up all these objects we've been creating?

My partner looked at me like I'd just suggested we put ice cubes on the pizza. Why would we do that?

They had, apparently, never needed to do that in their other django test suites. But why not?

I asked one of the other developers, and they said something about django's TestCase using transactions to roll back any changes to the database which were made during the test.

I rejected that explanation. If the test harness used transactions, I argued, then you couldn't test any code that used transactions itself, since you can't nest transactions.

Unfortunately we argued over that for a while longer without recognizing that we were arguing about facts, and this was something I could look up.

As it turns out, TestCase does wrap each test in a transaction. And yes, that does mean you can't test your own transactions in a TestCase; you'll need to use TransactionTestCase to do that. Those docs also provide this warning:

While commit and rollback operations still appear to work when used in TestCase, no actual commit or rollback will be performed by the database. This can cause your tests to pass or fail unexpectedly. Always use TransactionTestCase when testing transactional behavior.

I think that's going to do it for Week One, given that I'm four weeks behind and if that gap grows any further I may not be able to remember what point my notes were trying to make. There is, at the end of my week one notes, …and django test.client is horrible but I am not sure what lesson to take from that. Fear not, week-one developer, we'll get back to that in week four or five.

Footnotes:

  1. And as of Django 1.6, it uses a test runner which lets you have multiple test files. I was so happy to hear that that we upgraded to Django 1.6 that day. I would have really missed that feature otherwise, given that Twisted has had test discovery like that since Trial's inception in 2003.

    Alright, enough snootery, back to the djangoing!

    (If you are stuck on an earlier version of django, that test discovery functionality is available in django-discover-runner. Another super useful fact I learned from the Two Scoops book.)

  2. We're leaving aside, for the moment, the issue of how many models (and how much database interaction) should happen for a unit test. That's a topic we'll be revisiting many times to come, I think.