[TIP] How can self.r1 and self.r2 fixture records appear automagically when used?

Phlip phlip2005 at gmail.com
Fri Oct 29 23:04:12 PDT 2010

Hi. I'm a test-Nazi, currently working on a new greenfield project
with extremely tight Django requirements.

(Parenthetically: We recently switched from .JSON fixtures (with
SQLite3 :memory: and the transaction-test-cases trick) to Fixture.

(The time to test doubled, from 1 second to 2.5 seconds.

(I hope this implies Fixture will have a flatter response profile as
the number of fixture records and test cases go up!)

That said, I have a code tweak that I'd like help integrating directly
into Fixture. As a test-Nazi, I dislike this kind of test case:

  def test_stuff(self):
     r1 = Record.objects.get(name='r1')
     r2 = Record.objects.get(name='r2')
     assert r1.eats(r2)

Django makes simple record queries as verbose as raw SQL!

I prefer this:

  def test_stuff(self):
     assert self.r1.eats(self.r2)

The self.r1 and self.r2 fixture records appear automagically when used.

Below my sig is the __getattr__() needed to fetch them. But the code
currently binds with my specific object model. This is odious, because
self.fixture is available, so in theory the code could bind thru
Fixture and get the items by their internal class names - not their
name field, which might not exist.

The shim works by taking my_record_model, splitting off the model,
converting it to Model, and querying
Model.objects.get(name=my_record_model). This clearly limits the kinds
of names or other handles that target records can have.

Any idea how to refactor that?

(The shim class is called "SquirrelData" because I think Ruby's
"factory-girl" should be answered with "factory-squirrel". As


from my_app.models import *  #  eval() needs to see these models.
import re
from fixture.django_testcase import FixtureTestCase
from datasets.sample_database import db_fixture, ThangData, ThangAttributeData

class SquirrelData(FixtureTestCase):

    fixture = db_fixture
    datasets = [ThangData, ThangAttributeData]

    def __getattr__(self, attr):
        'CONSIDER  Merge this with the fixture project directly!'

        sought = re.search(r'^(.*)_([^_]+$)', attr)

        if sought:
            record_name, model_name = sought.groups()
            model = self._interpret_model(model_name)

            if model:
                record = model.objects.get(name=attr)
                setattr(self, attr, record)  #  So we needn't do it again.
                return record

        raise AttributeError("%r object has no attribute %r" %
                             (type(self).__name__, attr))

    def _interpret_model(self, model_name):
            return eval(model_name.capitalize())
        except NameError:
            return None

More information about the testing-in-python mailing list