I'm a noob on both Django and Python, so this question might be easy
for the experts out there. I am trying to do test first development
during the development of my model code. (I have lots of experience
with test first coding in the Java world, no practical experience in
the Py world.)
I want to do something like this
class ModelTest(TestCase):
def test_crud_modelone(self):
mo = ModelOne( name="A name" )
mo.save()
saved_mo = mo.objects.get(pk=mo.id)
assertEqual( vars(mo), vars(saved_mo),"Something not getting saved")
That assertEqual line fails. I wrote this
def compare(self, obj1, obj2, verbose = False):
other = vars(obj2)
for d,v in vars(obj1).items():
if isinstance(other.get(d,None),datetime.date):
if not other.get(d,None) == v.date():
return False
elif not other.get(d,None) == v:
return False
return True
This is probably horrible python, I'm still learning (unlearning
Java), but it compares correctly for strings and dates so far that
I've tested.
My questions are 1) Does anything like this already exist in Python
or Django that I should use? 2) If not, would something like this be
valuable to polish up and commit to the Django project?
Some might be asking why I'm testing if my models can be saved, as
most of that functionality is tested when Django is tested. But, I
still feel there's a enough that I have to write to warrant a simple
sanity test like this.
-- If I'm a million miles off base, I don't mind being told so. :)
--
Picante Solutions Limited
e: ge...@picante.co.nz
w: 06 757 9488
The assertEqual line (probably) fails because the order of dictionary
keys is not defined.
> Some might be asking why I'm testing if my models can be saved, as
> most of that functionality is tested when Django is tested. But, I
> still feel there's a enough that I have to write to warrant a simple
> sanity test like this.
FWIW I believe testing what you're testing is a waste of time and
violates unit testing. Really the db should be mocked, but that is
fairly hard. If you didn't write save(), you shouldn't be testing it.
But, if I were testing this I think I'd do something like this
assertEqual( db_mo, mo, "local and db versions of %s not
identical" % mo.__class__)
In general, I trust == (either Python's or the object's author's) more
than poking into the internals of an object, encapsulation and all that :)
When I compare dictionaries I either convert them to sorted tuples (to
put keys in proper order)
expected = dict(var1="dog", var2="cat")
answer = something_that_return_dict()
assertEqual( sorted(expected.items()), sorted(answer.items()) )
Or check only certain keys are equal (for instance if the answer dict
has other stuff in it I don't care about)
check_these = ["key1", "key3"] # = expected_dict.keys()
answer = something_that_return_dict()
for k in check_these:
self.assertEqual( expected_dict[k], answer[k],
"expected[%(key)s] != answer[%(key)s]" % {"key":k} )
For Models in which I write a custom save method this is how I usually
structure it.
def save(self):
if self.value is None:
self.value = self._calc_value()
super(FooModel, self).save()
def test_value_on_save(self):
test_data =( (dict(foo="", bar=""), 42 ),
(dict(foo="1", bar="3"), 37 ),
# test more edge cases, etc.
)
for (expected, data) in test_data
t = Model(**data)
t.save()
self.assertEqual( expected, t.value )
If I had another custom value I'd write another test for it.
Good luck with your continued Python adventures,
--
Norman J. Harman Jr.
Senior Web Specialist, Austin American-Statesman
___________________________________________________________________________
You've got fun! Check out Austin360.com for all the entertainment
info you need to live it up in the big city!
address4 = models.CharField(max_length=45, null=True, blank=True)
could be written as
address4 = models.CharField(max_length=45)
Were is the most reasonable place to test this is correct (not regressing)
What about uniqueness, and composite field uniqueness?
# unique_together = (("field1", "field2","field3"),)
I'm thinking it would make sense to try to
create 2 of an object and save them, and check that it fails
I'm not sure. I'm distraught over having validations in two places the
model and forms that "feed" that model. And form_from_model or whatever
it is called is never what I want. I tend to test the forms as I tend
to manipulate models through forms and the forms support much richer
validations than FooFields do.
Blank is an admin thing and I typically don't test those. Testing
Nullable field(s) would be data point(s) in creation/save test.
> What about uniqueness, and composite field uniqueness?
> # unique_together = (("field1", "field2","field3"),)
>
> I'm thinking it would make sense to try to
> create 2 of an object and save them, and check that it fails
Yep two of the objects whose 3 fields are not unique together.
There are a couple things going on here. One is that type-o.
The other is more of an open question as to what should be tested, and how.
I'm coming around to the this.
for each model I'll will
1) assume that clients that use the model code will test it indirectly.
2) test that nullable fields accept nulls (Perhaps this isn't
necessary - see 1)
3) test that unique constraints can't be violated.
4) test that all business methods function properly (with probably
the exception of __unicode__
Basically, if I can forget to state that model field should be unique,
then I can accidently remove that too. I'd like to have a test cover
it. But, if you leave off a whole field, some other test should fail,
or perhaps your app doesn't need the field.
(Note this is somewhat stream of thinking, and I'm not an expert at
Python or Django!)