After I left the Bureau approximately a month ago I’ve taken up a new role with Infoxchange Australia. My first project here is working on a rewrite of an application using Django.
People here are really into behaviour driven testing, and we’re using Lettuce to do it (using a branch with better Django integration).
I sort of dislike this sort of testing, because it creates an annoying abstraction layer on top of the code, with a poorly defined, quasi-real language. It’s like a bad knock off of Applescript. Anyway, I got sick of defining steps per model, so I put together some generic steps for manipulating Django models (that I’ll have to contribute back).
Anyway they look like this (examples of the step in the docstrings):
# build a hash of model verbose names to models
# this is used by get_model()
def _models_generator():
for model in get_models():
yield (model._meta.verbose_name, model)
yield (model._meta.verbose_name_plural, model)
MODELS = dict(_models_generator())
def get_model(model):
"""
Convert a model's verbose name to the model class. This allows us to
use the models verbose name in steps.
"""
name = model.lower()
model = MODELS.get(model, None)
assert model, "Could not locate model by name '%s'" % name
return model
def create_models(model, hashes):
for hash_ in hashes:
model.objects.create(**hash_)
def models_exist(model, hashes):
for hash_ in hashes:
assert \
model.objects.filter(**hash_).exists(), \
"Object does not exist"
@step(r'I have ([a-z][a-z0-9_ ]*) in the database:')
def create_models_generic(step, model):
"""
And I have admin field values in the database:
| name | value |
| project_type | Twine |
The generic method can be overridden for a specific model by defining a
function create_badgers(step), which creates the Badger model.
"""
try:
globals()['create_%s' % model](step)
except KeyError:
model = get_model(model)
create_models(model, step.hashes)
@step(r'(?:Given|And|Then) ([A-Z][a-z0-9_ ]*) with ([a-z]+) "([^"]*)" has ([A-Z][a-z0-9_ ]*) in the database:') # noqa
def create_models_for_relation(step, rel_model_name,
rel_key, rel_value, model):
"""
And project with name "Ball Project" has goals in the database:
| description |
| To have fun playing with balls of twine |
"""
lookup = {rel_key: rel_value}
rel_model = get_model(rel_model_name).objects.get(**lookup)
for hash_ in step.hashes:
hash_['%s_id' % rel_model_name] = rel_model.id
create_models_generic(step, model)
@step('(?:Given|And|Then) ([A-Z][a-z0-9_ ]*) should be present in the database')
def step_models_exist(step, model):
"""
And objectives should be present in the database:
| description |
| Make a mess |
"""
model = get_model(model)
models_exist(model, step.hashes)
@step(r'There should be (\d+) ([a-z][a-z0-9_ ]*) in the database')
def model_count(step, count, model):
"""
Then there should be 0 goals in the database
"""
model = get_model(model)
assert_equals(model.objects.count(), int(count))
