Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 56

Testing Django Views with Test Client

Recommended resources

Hello! Welcome to the next lesson in our module on testing.

In our last session, you wrote your first unit tests for Django models. You learned how to use TestCase and the "Arrange, Act, Assert" pattern to verify the custom logic within your models, ensuring the foundation of your application is solid.

Today, we're moving up the stack to test the user-facing part of your application: the views. You will learn how to use Django's test client to act like a web browser, making requests to your views and checking that they respond correctly. This is crucial for ensuring that your Task Manager's pages load as expected, display the right data, and handle user interactions properly.

By the end of this lesson, you will be able to write tests for your views that check for correct HTTP status codes and verify the data being sent to your templates.

1. Introducing the Django Test Client

To test a view, you need to simulate a web request to its URL and then inspect the response. Django provides a fantastic tool for this called the test client. It's a Python class that acts like a dummy web browser, allowing you to make GET, POST, and other requests directly from your test code.

Let's begin by reading the official documentation to understand what the test client is and how it works.

Writing your first Django app, part 5

This section from the official Django tutorial introduces the test client. It shows how you can use it to make a request and inspect the response, including the status code and the context.

Read the subsections 'A test for a view' and 'The Django test client'. Focus on how the client object is used to make a get request and how you can check response.status_code and response.context.

When you write tests inside a class that inherits from django.test.TestCase, you get a test client for free at self.client. As the documentation shows, the basic workflow is:

  1. Arrange: Create any necessary database objects your view will need.
  2. Act: Use self.client.get(url) or self.client.post(url, data) to make a request. It's best practice to use Django's reverse() function to generate the URL from its name, which makes your tests more robust to changes in your urls.py file.
  3. Assert: Check properties of the response object.

2. Testing a Simple View (GET Request)

Let's apply this to a common scenario: testing a list view. For your project, this would be the page that lists all of a user's tasks. The goal is to verify several things:

  • Does the page load successfully (Status Code 200)?
  • Does it use the correct HTML template?
  • Does it contain the data we expect?

The MDN guide you used in the previous lesson has a great, clear example of testing a ListView.

Django Tutorial Part 10: Testing a Django web application

This guide provides a step-by-step example of testing an AuthorListView. It covers everything from setting up test data to asserting the status code, template, and context.

Read the section titled 'Views'. Pay close attention to the AuthorListViewTest class. Note how it uses setUpTestData, self.client.get(reverse('...')), assertEqual(response.status_code, 200), and assertTemplateUsed(response, ...).

As you saw in the reading, a typical test for a list view looks like this:

from django.test import TestCase
from django.urls import reverse
# from .models import YourModel

class YourListViewTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        # ARRANGE: Create some objects for the view to list.
        # YourModel.objects.create(...)

    def test_view_url_exists_at_desired_location(self):
        # ACT: Make a GET request to the view's URL.
        response = self.client.get('/your-url-path/')
        # ASSERT: Check that the response was successful.
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('your-view-name'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('your-view-name'))
        self.assertEqual(response.status_code, 200)
        # ASSERT: Check that the correct template was used to render the page.
        self.assertTemplateUsed(response, 'your_app/your_template.html')

3. Verifying the View's Context

A successful status code and the correct template are good, but the most important test is verifying that the data sent to the template is correct. This data lives in the response.context dictionary.

For a list view, you typically want to check that the list of objects in the context matches the objects you created in your test setup.

The Django tutorial provides an excellent example of this using assertQuerySetEqual.

Writing your first Django app, part 5

This section of the Django tutorial demonstrates how to specifically test the context data of a view.

Re-examine the code in the 'Testing our new view' section. Focus on the test_past_question and test_two_past_questions methods. See how they use assertQuerySetEqual to check that the latest_question_list in the context contains the exact questions they expect.

Using assertQuerySetEqual is a powerful way to confirm that your view's query is fetching the correct objects. For your Task Manager, you could use it to verify that the task list page only shows tasks belonging to the logged-in user and not tasks from other users.

Test your understanding!

Imagine you're testing the detail view for a specific task (e.g., /tasks/5/). If a user tries to access a task that doesn't exist (e.g., /tasks/999/), what HTTP status code should your view return, and how would you assert this in your test?

Show answer

The view should return a 404 Not Found status code. Your test assertion would look like this:
self.assertEqual(response.status_code, 404)


4. Testing Protected Views and User-Specific Data

Your Task Manager will have views that should only be accessible to logged-in users. Testing this is critical for security. The test client gives you tools to handle this.

Let's watch a video that demonstrates the whole process of testing views, including how to handle different request types like GET, POST, and DELETE. While watching, focus on how the tests are structured for clarity.

Django Testing Tutorial - Testing Views #3

This video from The Dumbfounds provides a concise and practical walkthrough of testing views. It covers making requests, checking status codes, and verifying that database objects are created or deleted as expected.

Watch from the beginning until 06:38. This will cover: Setting up the test class with self.client. Testing a GET request for a list view (checking status code and template). Testing a GET request for a detail view, including how to create test data in the setUp method to avoid a 404 error.

Now, let's learn how to test views that require a user to be logged in. The MDN guide provides a clear example of this common and important scenario.

Django Tutorial Part 10: Testing a Django web application

This resource explains how to test views that are protected with LoginRequiredMixin or the @login_required decorator.

Navigate back to the 'Views' section you read earlier and focus on the subsection titled 'Views that are restricted to logged in users'. Pay close attention to: self.client.login(): How to log a test user in. assertRedirects(): How to check that a non-logged-in user is redirected to the login page.

This pattern is fundamental for your project:

  1. Test for redirect: First, write a test that accesses the protected URL without logging in. Assert that the response is a redirect (status code 302) to the login page.
  2. Test for success: Next, write a test where you create a user, log them in with self.client.login(username='...', password='...'), and then access the URL. Assert that the status code is now 200.

This two-step process ensures your view is correctly protected.


Conclusion

You have now learned the essential techniques for testing Django views. You can simulate user requests, verify responses, and ensure that your application's pages are behaving correctly, both for public and protected content.

Key Takeaways:

  • The Django test client (self.client) is your primary tool for testing views, allowing you to simulate GET and POST requests.
  • Always use reverse() to generate URLs in your tests to make them more maintainable.
  • Essential assertions for view tests include:
    • self.assertEqual(response.status_code, ...) to check for success (200), redirects (302), not found (404), etc.
    • self.assertTemplateUsed(response, ...) to ensure the correct template is rendered.
    • self.assertEqual(response.context['key'], ...) or self.assertQuerySetEqual(...) to verify the data passed to the template.
  • For protected views, test that unauthenticated users are redirected, then use self.client.login() to test the authenticated user experience.

Preview of the Next Lesson:

We've touched upon client.post() today, but we haven't dived deep into what happens when a user submits a form. In our next lesson, we will focus specifically on that: writing tests to simulate form submissions and validate form logic. You'll learn how to check for form errors and verify that valid data correctly creates or updates objects in your database.