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 usage of a generic view class comprises a simple method override. Invoking the entire view and the Django request/response stack is a waste of time… you really want to test the overridden method directly.

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 MyViewClass(generic.DetailView)

    def get_context_data(self, **kwargs):
        kwargs = super(MyViewClass, self).get_context_data(**kwargs)
        if hasattr(self.request, 'some_data'):
            kwargs.update({
                'some_data': self.request.some_data
            })
        if hasattr(self, 'special_value'):
            kwargs.update({
                'special_value': self.special_value
            })
        return kwargs

class MyViewTests(CBVTestCase):

    def test_context_data(self):
        my_view = self.get_instance(MyViewClass, initkwargs={'special_value': 42})
        context = my_view.get_context_data()
        self.assertContext('special_value', 42)

    def test_request_attribute(self):
        request = django.test.RequestFactory().get('/')
        request.some_data = 5
        my_view = self.get_instance(MyViewClass, request=request)
        context = my_view.get_context_data()
        self.assertContext('some_data', 5)

get(cls, *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(MyViewClass)
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().

If you need special request attributes, i.e. ‘user’, you can create a custom Request with RequestFactory, assign to request.user, and use that in the get():

def test_request_attribute(self):
request = django.test.RequestFactory().get(‘/’) request.user = some_user self.get(MyViewClass, request=request, pk=data.pk) self.assertContext(‘user’, some_user)

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, *args, **kwargs)

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

Example:

response = self.post(MyViewClass, 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().

If you need special request attributes, i.e. ‘user’, you can create a custom Request with RequestFactory, assign to request.user, and use that in the post():

def test_request_attribute(self):
request = django.test.RequestFactory().post(‘/’) request.user = some_user self.post(MyViewClass, request=request, pk=self.data.pk, data={}) self.assertContext(‘user’, some_user)

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().