Flickr Badge

Tuesday, March 25, 2008

Why doesn't Django find my unit tests?

I ran into a Django gotcha today. I had an app for which it was simply not running the unit tests. The tests were there in the correct location. Django was correctly running the tests for all the other apps. Why was it not running the tests for this one? I checked settings.py to see if the app was in INSTALLED_APPS. It was. It worked fine through the browser, and the test code looked good. What was worse, it was working when I last ran it before the weekend. Why did it suddenly stop running?

I got my answer after some digging around in the Django source. It appears that you must have models.py in the app for tests to run. It so happened that this app has no models, only some views that do some calculations. Since models.py was empty, I had deleted it and didn't think too much about it. Whoops! The tests stopped running.

Once I had that figured out, the solution was simple - recreate the empty models.py, and the tests started running again.

This whole thing is really unintuitive though. Who would have thought that removing an empty file would cause the tests to stop running? There doesn't seem to be any connection between them at all.

In a broader sense, any piece of code that uses django.db.models.get_apps to get a list of installed apps is likely to run into this problem. Don't be surprised if you remove an empty models.py and then something breaks and you are left scratching your head as to what exactly happened.

This is exactly the kind of unintuitive "magic" that we Pythonistas hate :) Explicit is better than implicit etc.

What I don't understand is that the list of installed apps *IS* explicit. It's sitting there called INSTALLED_APPS in settings.py. Why does Django go about hunting through the models when it could just read this value? Any clues?

3 comments:

Brian Luft said...

I ran into this as well under different circumstances. I was using a 3rd party app but was storing fixture data for it under my own app which did not include a models.py. Went crazy for a while trying to figure out why syncdb would not pick up that particular fixture.

I think I'll look into a bug report...

Brian Luft said...

FYI I opened up Ticket #6883 for this.

Siddhi said...

Hi Brian, Just noticed that your ticket was closed because it was already reported. I searched around and found Ticket #3310.

There is a patch available on that ticket that supposedly fixes this issue (I have to try it out)

Activity on the ticket seems to have stopped about half a year ago. Maybe I'll try adding some tests to that patch and see if it goes anywhere.