[Django]-How do I test Django views when they don't return values

3👍

Actually, Django’s generic class-based views are not called generic for no reason.

You can view the source of the both ListView and CreateView.


The ListView has a GET method handler:

class BaseListView(MultipleObjectMixin, View):
    """A base view for displaying a list of objects."""
    def get(self, request, *args, **kwargs):
        self.object_list = self.get_queryset()
        allow_empty = self.get_allow_empty()

        if not allow_empty:
           # ...

        context = self.get_context_data()
        return self.render_to_response(context)

Which returns a valid Django response and can be tested in tests.py.


If you look at the CreateView, it inherits from BaseCreateView (just like ListView inherits from BaseListView):

class BaseCreateView(ModelFormMixin, ProcessFormView):
    """
    Base view for creating an new object instance.
    Using this base class requires subclassing to provide a response mixin.
    """
    def get(self, request, *args, **kwargs):
        # ...

    def post(self, request, *args, **kwargs):
        # ...

Which also inherits from ProcessFormView:

class ProcessFormView(View):
    """Render a form on GET and processes it on POST."""
    def get(self, request, *args, **kwargs):
        """Handle GET requests: instantiate a blank version of the form."""
        return self.render_to_response(self.get_context_data())

    def post(self, request, *args, **kwargs):
        """
        Handle POST requests: instantiate a form instance with the passed
        POST variables and then check if it's valid.
        """
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

The GET request will result in a valid response. As you see, the POST method handler here returns either self.form_valid(form) or self.form_invalid(form) depending on the form status.

You can see the source of these two methods in ViewMixin:

def form_valid(self, form):
    """If the form is valid, redirect to the supplied URL."""
    return HttpResponseRedirect(self.get_success_url())

def form_invalid(self, form):
    """If the form is invalid, render the invalid form."""
    return self.render_to_response(self.get_context_data(form=form))

Both of these methods return a valid testable Django responses.


In conclusion, both of your ListBlogPostView and CreateBlogPostView can be directly tested in tests.py. You just need to have a more detailed look at the implementation of Django’s generic views. The power of open-source!

1👍

Testing view unlike function most of the time will not have a return value. The way that I go about doing it is to assert the html response.

So for the ListBlogPostView it depends on what is in the blogpost_list.html template.

A general view test should look like this:

class ListBlogPostViewTest(TestCase):

    def test_blogpost_list_view(self): 
        response = self.client.get(reverse('blogpost-list'))
        html = response.content.decode('utf8')  
        self.assertTrue(html.startswith('<html>'))
        self.assertIn('<title>BlogPost lists</title>', html)  
        self.assertTrue(html.endswith('</html>'))

For view that have context you can actually check if it is being retrieved and passed correctly to view.

blogPost = BlogPost.object.get(id=1)
self.assertEqual(response.context['blogPost'].name, blogPost.name)

How could I ever use a TDD approach to Django?

As for TDD, you just have to test the html view first before creating it. It really depend on how detail you like to test and find the balance for it. I prefer to test mainly on the context being set and important html element is in the view.

0👍

You can still surely test lot of parameters –

  • status code on get and post request
  • variables in context data (such as form)
  • assert template used
  • creation of object on post request in case of create view
  • check for permissions using status codes

The thing is tests on django views are technically integration tests. As long as your tests are granular enough, means you don’t test code for forms or models in views, I don’t see any problem provided you follow Classical TDD.

Leave a comment