Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test methods inside django's class based views?

I need to test the methods and helper function inside a django Class Based View.

Consider this Class Based View:

class MyClassBasedView(View):

    def dispatch(self, request, *args, **kwargs):
        ....

    def __get_render_dict():
        d = {}
        ...
        return d

    def my_method(self):
        render_dict =  self.__get_render_dict()
        return render_response(self.request, 'template.html', render_dict)

In order to write unit tests for my view, I need to call the methods inside, say __get_render_dict() directly. How can I achieve this?.

I've tried

v = MyClassedBasedView() 
v.dispatch(request,args, kwargs)
v.__method_name()

but this fails with not matching parameters in post/get method, even though I was calling the method direclty without using URL.

like image 671
totoro Avatar asked Nov 11 '15 07:11

totoro


People also ask

How do you unit test methods?

A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.

Which is better class-based views or function based views in Django?

There are cases where function-based views are better. In other cases class-based views are better. For example, if you are implementing a list view, and you can get it working just by subclassing the ListView and overriding the attributes. Great.

Does every method need a unit test?

Every behavior should be covered by a unit test, but every method doesn't need its own unit test. Many developers don't test get and set methods, because a method that does nothing but get or set an attribute value is so simple that it is considered immune to failure.


3 Answers

To use class based views in your unittests try setup_view from here.

def setup_view(view, request, *args, **kwargs):
    """
    Mimic ``as_view()``, but returns view instance.
    Use this function to get view instances on which you can run unit tests,
    by testing specific methods.
    """

    view.request = request
    view.args = args
    view.kwargs = kwargs
    return view

You still need to feed it a request, you can do this with django.test.RequestFactory:

    factory = RequestFactory()
    request = factory.get('/customer/details')

You can then unittest your methods:

v = setup_view(MyClassedBasedView(), request) 
v.method_name()
like image 159
Sebastian Wozny Avatar answered Oct 19 '22 21:10

Sebastian Wozny


Update - available in Django 3.0

As stated in Sebastian's answer he got the code snippet from django-downloadview docs. In there they state:

This is an early implementation of https://code.djangoproject.com/ticket/20456

A few years later, this feature is now part of Django, as you can read in the docs, so you would just need to do:

from django.test import RequestFactory, TestCase
from .views import MyClassBasedView

class MyClassBasedViewTest(TestCase):
  def test_my_method(self):
    request = RequestFactory().get('/')
    view = MyClassBasedView()
    view.setup(request)

    view.my_method()

The view.setup() method is precisely what was suggested in the accepted answer, but I think it is better to use the one from Django :)

like image 15
NBajanca Avatar answered Oct 19 '22 21:10

NBajanca


I solved this issue by doing MyClassedBasedView.as_view()(request)

like image 9
Thom Avatar answered Oct 19 '22 21:10

Thom