Video thumbnail for Learn Django TDD - Test Driven Development - CRUD

Django TDD Tutorial: Build a CRUD App with Test Driven Development

Summary

Quick Abstract

Unlock the power of Test-Driven Development (TDD) in Django! This summary guides you through building a simple CRUD app, emphasizing writing tests before code. Discover how TDD ensures code reliability and improves design. Learn to set up a Django project and app, then dive into creating model, view, and form tests. We'll cover testing model existence, string representation, template usage, status codes, form validation, redirects, and more!

Quick Takeaways:

  • Learn to create a Django project and app for task management.

  • Write tests before code for models, views (index, detail, new, update, delete), and forms.

  • Master Django's testing tools: TestCase, assertTemplateUsed, assertContains, assertRedirects.

  • Test form validity, error handling, and data persistence.

  • Build tests for creating, reading, updating, and deleting tasks.

Introduction

In this video, we'll learn the basics of testing in Django while building a simple CRUD application. The form of testing we'll focus on is Test-Driven Development (TDD), where we write tests before writing the actual code.

What is TDD?

TDD might seem strange and redundant at first, but it's a popular approach that ensures your code works better. It also makes it easier to write high-quality code as you have to clearly define the problem before starting to build.

Setting Up the Django Project

First, make sure Django is installed. Then, create a new project named tdd_testing using the command django-admin startproject tdd_testing. Navigate into the project directory and open it in your preferred editor.

Creating the Tasks App

We'll create an app for tasks as we're building a to-do application. In the terminal, run python manage.py startapp task. Then, open the settings.py file and register the task app.

Writing the First Test

Even though we haven't written any code yet, we can start testing. Open the tests.py file in the task app. The first test will check if there's a Django model for tasks and if there are no tasks in the database by default.

Testing the Task Model Existence

Create a test class named TaskModelTest that inherits from TestCase (already imported from Django). Inside the class, write a test function test_task_model_exists. In this function, try to get the count of tasks from the database. Since no tasks should exist yet, assert that the count is zero.

Creating the Task Model

Running the test will result in an error as the task model isn't defined. So, create the Task model in the models.py file. The model will have a title field (a character field with a maximum length of 255) and a description field (a text field that can be blank).

Running Migrations

After creating the model, we need to run migrations to create the corresponding database table. Run python manage.py make migrations and then python manage.py migrate. Now, running the test should pass.

Testing the String Representation of the Task Model

Next, we'll test the string representation of the Task model. We want it to return the title by default instead of the class name. Create a new test function test_model_has_string_representation in the TaskModelTest class. First, create a task in the database, then assert that the string representation of the task is equal to its title.

Fixing the String Representation

The test will fail as the default string representation is the class name. To fix this, add a __str__ method to the Task model in models.py that returns the title. After that, update the test to convert the string representation to a string before comparing.

Testing the Index Page

Now, let's move on to testing the index page. Create a new test class IndexPageTest that inherits from TestCase. Write a test function test_index_page_returns_correct_response to check if the index page returns a 200 status code and uses the correct template (task/index.html).

Creating the Index View and URL

The test will fail as we haven't created the index view yet. In the views.py file, create an index view that renders the task/index.html template. Then, create a new urls.py file in the task app, import the views, and set up the URL patterns to map the root URL to the index view. Import the task.urls into the main urls.py file.

Creating the Index Template

Running the test will now show that the template doesn't exist. Create a templates folder inside the task app, then a task folder inside templates, and finally an index.html template.

Testing if the Index Page Lists Tasks

We'll test if the index page lists out tasks. Create a new test function test_index_page_has_tasks in the IndexPageTest class. First, get the response from the index page, then create a task in the database, and finally assert that the response contains the task's title.

Updating the Index View and Template

The test will fail as the index view and template don't display the tasks. Update the index view to get all tasks from the database and pass them to the template. Then, update the index.html template to loop through the tasks and display their titles.

Testing the Detail Page

Next, we'll test the detail page where we can view the description of a task. Create a new test class DetailPageTest that inherits from TestCase. In the setUp method, create a task with a description.

Testing the Detail Page Response

Write a test function test_detail_page_returns_correct_response to check if the detail page returns a 200 status code and uses the correct template (task/detail.html). Pass the task's ID in the URL when getting the response.

Creating the Detail View and URL

The test will fail as the detail view doesn't exist. Create a detail view in views.py that gets the task from the database based on the primary key in the URL and renders the task/detail.html template. Update the urls.py file in the task app to map the URL with the task ID to the detail view.

Creating the Detail Template

Running the test will show that the template doesn't exist. Create a detail.html template in the task templates folder.

Testing the Content of the Detail Page

We'll test if the detail page shows the correct task title and description. Create a new test function test_detail_page_has_correct_content in the DetailPageTest class. Get the response from the detail page and assert that it contains the task's title and description.

Testing Multiple Tasks on the Detail Page

We also want to make sure that the detail page doesn't show other tasks. In the setUp method of the DetailPageTest class, create a second task. Then, in the test_detail_page_has_correct_content function, assert that the response doesn't contain the title of the second task.

Testing the New Page

Now, let's test the new page where we can create tasks. Create a new test class NewPageTest that inherits from TestCase. Write a test function test_new_page_returns_correct_response to check if the new page returns a 200 status code and uses the correct template (task/new.html).

Creating the New View and URL

The test will fail as the new view doesn't exist. Create a new view in views.py that renders the task/new.html template. Update the urls.py file in the task app to map the /new URL to the new view.

Creating the New Template

Running the test will show that the template doesn't exist. Create a new.html template in the task templates folder.

Testing the Task Form

We'll use forms to create tasks in Django. Create a new forms.py file in the task app, import the necessary modules, and create a NewTaskForm class that inherits from forms.ModelForm. The form will use the Task model and include the title and description fields.

Testing the Form

In the tests.py file, import the NewTaskForm and write tests to check if the form is a subclass of forms.ModelForm, if the title and description fields are in the form's meta, and if the form is valid when provided with data.

Testing if the New Page Renders the Form

Create a new test function test_new_page_form_rendering in the NewPageTest class. Get the response from the new page and assert that it contains the form tag, the CSRF middleware token, and a label for either the title or description field.

Updating the New View and Template

The test will fail as the new view doesn't pass the form to the template and the template doesn't render the form. Update the new view to create an instance of the NewTaskForm and pass it to the template. Then, update the new.html template to display the form.

Testing Invalid Forms

We'll test what happens when an invalid form is submitted. In the test_new_page_form_rendering function, create a new test for an invalid form. Submit a form with an empty title and assert that the response contains the error list and the "This field is required" error message.

Handling Form Submission in the New View

The test will fail as the new view doesn't handle form submission. Update the new view to handle POST requests, create a form instance from the request data, save the form if it's valid, and create an empty form instance if it's invalid.

Testing Form Redirection

We'll test if a valid form submission redirects to the front page. Create a new test function test_valid_form in the NewPageTest class. Submit a valid form, assert that the response redirects to the front page, and that there is one task in the database.

Updating the New View for Redirection

The test will fail as the new view doesn't redirect after a valid form submission. Update the new view to return a redirect to the front page after saving the form.

Testing the Update Page

Next, we'll test the update page where we can update a task. Create a new test class UpdatePageTest that inherits from TestCase. In the setUp method, create a task.

Testing the Update Page Response

Write a test function test_update_page_returns_correct_response to check if the update page returns a 200 status code and uses the correct template (task/update.html). Pass the task's ID in the URL when getting the response.

Creating the Update View and URL

The test will fail as the update view doesn't exist. Create an update view in views.py that gets the task from the database based on the primary key in the URL and renders the task/update.html template. Update the urls.py file in the task app to map the /update/<int:primary_key> URL to the update view.

Creating the Update Template

Running the test will show that the template doesn't exist. Create an update.html template in the task templates folder.

Testing the Update Form

We'll create an UpdateTaskForm in the forms.py file, which is similar to the NewTaskForm. In the tests.py file, write tests to check if the form is valid when provided with data and if it updates the task in the database.

Updating the Update View and Template

The test will fail as the update view doesn't pass the form to the template and the template doesn't render the form. Update the update view to create an instance of the UpdateTaskForm with the task instance, pass it to the template, and handle form submission. Then, update the update.html template to display the form.

Testing the Delete Page

Finally, we'll test the delete page where we can delete a task. Create a new test class DeletePageTest that inherits from TestCase. In the setUp method, create a task.

Testing the Delete Page

Write a test function test_delete_page_actually_delete_a_task to check if the delete page deletes the task, redirects to the front page, and leaves zero tasks in the database.

Creating the Delete View and URL

The test will fail as the delete view doesn't exist. Create a delete view in views.py that deletes the task from the database and redirects to the front page. Update the urls.py file in the task app to map the /delete/<int:primary_key> URL to the delete view.

Conclusion

We've now created tests for a full CRUD application in Django using TDD. If you liked this tutorial, please hit the like button, subscribe to the channel, and click the bell for notifications when new videos are published. See you in the next video!

Was this summary helpful?

Quick Actions

Watch on YouTube

Related Summaries

No related summaries found.

Summarize a New YouTube Video

Enter a YouTube video URL below to get a quick summary and key takeaways.