Dec

11

Testy

Anyone attempting to dip into my modest archive this morning would have seen an error message instead. (And yes, the error page itself isn't getting styled properly. One thing at a time, people!)

I discovered a bug in how my archive_month view was working and I fixed it. And in the process I opened a much worse bug. This is one of the classic narratives, along with "boy meets girl", "stranger comes to town" and the rest.

Here's the way the view looked this morning:

def archive_month(request, year, month, category_slug=None):
queryset = BlogPost.objects.public_posts()
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
queryset = queryset.filter(category=category)
 
return date_based.archive_month(
request,
year=year,
month=month, month_format="%B",
date_field='pub_date',
queryset=queryset,
template_object_name='blogpost',
extra_context={'category': category, 'preview': True}
)

So close...

Now, here it is, with the fix:

def archive_month(request, year, month, category_slug=None):
queryset = BlogPost.objects.public_posts()
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
queryset = queryset.filter(category=category)
else:
category = None
 
return date_based.archive_month(
request,
year=year,
month=month, month_format="%B",
date_field='pub_date',
queryset=queryset,
template_object_name='blogpost',
extra_context={'category': category, 'preview': True}
)

Now category is always set, whether it's to a Category object or to None. No more "UnboundLocalError: local variable 'category' referenced before assignment".

But when I realized I was going to post my fix, I also realized I would have to write a couple tests and put them up too, or risk losing even more face.

class ArchiveMonthTestCase(TestCase):
fixtures = ['test.json']
 
def setUp(self):
self.client = client.Client()
 
def testWithoutCategoryLoads(self):
response = self.client.get(reverse('blog_archive_month', None, (),
{'year': '2008', 'month': 'november'}))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'blog/blogpost_archive_month.html')
self.failUnless('category' in response.context[-1])
self.assertEqual(response.context[-1]['category'], None)
self.failUnless('month' in response.context[-1])
self.assertEqual(response.context[-1]['month'].year, 2008)
self.assertEqual(response.context[-1]['month'].month, 11)
 
def testWithCategoryLoads(self):
category = Category.objects.all()[0]
response = self.client.get(reverse('category_archive_month', None, (),
{'category_slug': category.slug,
'year': '2008',
'month': 'november'}))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'blog/blogpost_archive_month.html')
self.failUnless('category' in response.context[-1])
self.assertEqual(response.context[-1]['category'], category)
self.failUnless('month' in response.context[-1])
self.assertEqual(response.context[-1]['month'].year, 2008)
self.assertEqual(response.context[-1]['month'].month, 11)

I'm starting to think that these basic tests that just confirm that your site can render all its pages are the best part of any test suite. They're dead easy to write, they provide some clarity about what pages you have and what they do, and they should help prevent the sort of knuckleheaded bug that I introduced 12 hours ago.