Seconds ago I got this running and haven't yet fully understood what I've just done but the results are exactly what I need and this is going to be great.

Basically, in Django you have views like this:


def _render(template, data, request):
   return render_to_response(template, data,
             context_instance=RequestContext(request))

@login_required
def club_page(request, year):
   variable1 = year / 4
   variable2 = variable1 * 2
   return _render("foo.html", locals(), request)

Now in my unit tests I don't want to have to call the view function and then have to dissect the resulting HTML just to figure out if the view function prepared the correct variables. So, here's my solution to this problem:

In 'test_views.py':


from my_app.views import club_page

# mutable globals for capturing the traffic through _render
snatched_templates = []
snatched_data = []
snatched_requests = []
def _fake_render(template, data, request):
   snatched_templates.append(template)
   snatched_data.append(data)
   snatched_requests.append(request)
   return render_to_response(template, data,
             context_instance=RequestContext(request))

class FakeRequest(object):
   def __init__(self, get=None, post=None, user=None):
       self.get = get
       self.post = post
       self.user = user

   def GET(self):
       return self.get

   def POST(self):
       return self.post

class ViewsTestCase(unittest.TestCase):
   def test_club_page(self):

        # add a test user
       from django.contrib.auth.models import User
       user = User.objects.create_user(username='t', password='t', 
                email='t@t.com')

       # prepare a request 
       request = FakeRequest(user=staff)

       from my_app import views
       views._render = _fake_render

       response = club_day_page(request, 'fool', 2004)
       assert response.count('</html>')
       assert snatched_data[-1]['variable2'] == 102

This isn't really something a novice test driven Django developer can just copy since I've scribbled this code as pseudo code. My code for my app is a bit more complicated than this but the principle is the same.

So, tell me Django gurus, have I reinvented the wheel here or are other people finding this useful?

UPDATE

There is a more convenient way but it's quite arcane. After a client request has been made the response has an attribute context that you can use. E.g.:


response = client.get('/club/Test_club2/attendance-report/')
context_data = response.context[-1].dicts[0]
pprint(context_data)

This approach, unlike my hack mentioned first, however requires that you have a publishable URL first.

Thanks Stephen!

Comments

James Bennett

The Django unit-testing documentation covers much easier ways to do this. For real-world examples, see the unit-test suite in the in-progress rewrite of my user-registration app:

http://bitbucket.org/ubernostrum/django-registration-backends/src/tip/registration/tests.py#cl-315

Peter Bengtsson

404 on that.

Your email will never ever be published.

Previous:
Why do you vote for the democrats? November 3, 2008 Politics
Next:
domstripper - A lxml.html test project November 20, 2008 Python
Related by category:
How to avoid a count query in Django if you can February 14, 2024 Django
How to have default/initial values in a Django form that is bound and rendered January 10, 2020 Django
My site's now NextJS - And I (almost) regret it already December 17, 2021 Django
How to sort case insensitively with empty strings last in Django April 3, 2022 Django
Related by keyword:
Mocking os.stat in Python November 8, 2009 Python
Gamification for me as a software developer December 21, 2012 Web development
Django vs. Java October 25, 2008 Django
Google London Automation Test conference September 8, 2006 Work