Testing class-based “generic” views

The TestCase methods get() and post() work for both function-based and class-based views. However, in doing so they invoke Django’s URL resolution, middleware, template processing, and decorator systems. For integration testing this is desirable, as you want to ensure your URLs resolve properly, view permissions are enforced, etc. For unit testing this is costly because all these Django request/response systems are invoked in addition to your method, and they typically do not affect the end result.

Class-based views (derived from Django’s generic.models.View class) contain methods and mixins which makes granular unit testing (more) feasible. Quite often your usage of a generic view class comprises a simple override of an existing method. Invoking the entire view and the Django request/response stack is a waste of time... you really want to call the overridden method directly and test the result.

CBVTestCase to the rescue!

As with TestCase above, simply have your tests inherit from test_plus.test.CBVTestCase rather than TestCase like so:

from test_plus.test import CBVTestCase

class MyViewTests(CBVTestCase):

Methods

get_instance(cls, initkwargs=None, request=None, *args, **kwargs)

This core method simplifies the instantiation of your class, giving you a way to invoke class methods directly.

Returns an instance of cls, initialized with initkwargs. Sets request, args, and kwargs attributes on the class instance. args and kwargs are the same values you would pass to reverse().

Sample usage:

from django.views import generic
from test_plus.test import CBVTestCase

class MyClass(generic.DetailView)

    def get_context_data(self, **kwargs):
        kwargs['answer'] = 42
        return kwargs

class MyTests(CBVTestCase):

    def test_context_data(self):
        my_view = self.get_instance(MyClass, {'object': some_object})
        context = my_view.get_context_data()
        self.assertEqual(context['answer'], 42)

get(cls, initkwargs=None, *args, **kwargs)

Invokes cls.get() and returns the response, rendering template if possible. Builds on the CBVTestCase.get_instance() foundation.

All test_plus.test.TestCase methods are valid, so the following works:

response = self.get(MyClass)
self.assertContext('my_key', expected_value)

All test_plus TestCase side-effects are honored and all test_plus TestCase assertion methods work with CBVTestCase.get().

NOTE: This method bypasses Django’s middleware, and therefore context variables created by middleware are not available. If this affects your template/context testing you should use TestCase instead of CBVTestCase.

post(cls, data=None, initkwargs=None, *args, **kwargs)

Invokes cls.post() and returns the response, rendering template if possible. Builds on the CBVTestCase.get_instance() foundation.

Example:

response = self.post(MyClass, data={'search_term': 'revsys'})
self.response_200(response)
self.assertContext('company_name', 'RevSys')

All test_plus TestCase side-effects are honored and all test_plus TestCase assertion methods work with CBVTestCase.post().

NOTE: This method bypasses Django’s middleware, and therefore context variables created by middleware are not available. If this affects your template/context testing you should use TestCase instead of CBVTestCase.

get_check_200(cls, initkwargs=None, *args, **kwargs)

Works just like TestCase.get_check_200(). Caller must provide a view class instead of a URL name or path parameter.

All test_plus TestCase side-effects are honored and all test_plus TestCase assertion methods work with CBVTestCase.post().

assertGoodView(cls, initkwargs=None, *args, **kwargs)

Works just like TestCase.assertGoodView(). Caller must provide a view class instead of a URL name or path parameter.

All test_plus TestCase side-effects are honored and all test_plus TestCase assertion methods work with CBVTestCase.post().