Examples of using Doctests in Django in an Agile / BDD way
Question: I'm interested in learning how to Doctests and Unit tests in a more Agile /
BDD way. I've found a few tutorials that seem reasonable, but they are just
thumbnails. What I would really like to see is the source code of some Django
projects that were developed BDD style.

The things I'm unclear about are how do you handle request objects etc. I have
a situation where I have deployed my app and I'm getting completely different
behavior in production that I did in development or even from the Python shell
on the production server. I'm hoping some Doctests will help me diagnose this
and well as open the door for a more Agile process of writing the tests first.

Specifically, here is the code I'm trying to test:

    
    
    def match_pictures_with_products( queryset, number_of_images = 3):      
        products = []  
        i = 0    
        for product in queryset:  
           if i < ( number_of_images ):  
               image =  product.imagemain_set.all()[:1]  
               product.photo_url = image[0].photo.url  
    
           products.append(product)  
           i += 1  
    
        return products  
    
    def index(request):  
        """returns the top 10 most clicked products"""     
        products = Product.objects.all()[:10]  
        products = match_pictures_with_products( products, 10)  .  
        return render_to_response('products/product_list.html', {'products': products})
    

How do I create a Doctest that ensures that index returns 10 objects?  
The Product queries seem to work fine from the shell on the production server.
The actual server is not returning any products at all.


Answer: I've asked myself the same question before. I've found doctests to be of
limited utility for things like views, model methods and managers because

  1. You need to be able to setup and teardown a test data set to actually use for testing
  2. Views need to take a request object. In a doctest, where does that come from?

For that reason, I've always used the Django [unit
testing](http://docs.djangoproject.com/en/1.1/topics/testing/#writing-unit-
tests) framework which handles all this for you. Unfortunately, though, you
don't get some of the benefits of the doctests and it makes TDD/BDD harder to
do. What follows next is **pure speculation** about how you might make this
work:

I think you'd want to grab doctests from their respective modules and
functions and execute them within the unit testing framework. This would take
care of test data setup/teardown. If your doctests were executed from within a
test method of something that subclasses Django's unittest.TestCase they'd be
able to use that test DB. You'd also be able to pass a mock request object
into the doc test's execution context. Here's a [Django
snippet](http://www.djangosnippets.org/snippets/963/) that provides a mock
request object and [info](http://groups.google.com/group/django-
developers/browse%5Fthread/thread/db86050095ebe5db) on it. Let's say you
wanted to test the docstrings from all of an applications views. You could do
something like this in tests.py :

    
    
    from ??? import RequestFactory
    from doctest import testmod, DocTestFailure
    from django.test import TestCase
    
    from myapp import views
    
    class MyAppTest(TestCase):
    
        fixtures = ['test_data.json']
    
        def test_doctests(self):                
            try:
                testmod(views, extraglobs={
                    'REQUEST': RequestFactory()
                }, raise_on_error=True)
            except DocTestFailure, e:
                self.fail(e)
    

This _should_ allow you to do something like this:

    
    
    def index(request):  
        """
        returns the top 10 most clicked products
    
        >>> response = index(REQUEST)
        >>> [test response content here]
    
        """     
        products = Product.objects.all()[:10]  
        products = match_pictures_with_products( products, 10)  .  
        return render_to_response('products/product_list.html', {'products': products})
    

Again, this is just off the top of my head and not at all tested, but it's the
only way that I think you could what you want without just putting all your
view tests in the unit testing framework.

