Wednesday, November 12, 2025

thumbnail

Test-Driven Development (TDD) with Python and Django

 🧠 What Is Test-Driven Development (TDD)?


Test-Driven Development (TDD) is a software development approach where you write tests before writing the actual code.


It follows a simple but powerful three-step cycle:


Red – Write a test that fails.


Green – Write the minimal code needed to make the test pass.


Refactor – Clean up the code while keeping all tests passing.


This process ensures your code:


Does exactly what it should.


Is easier to maintain.


Is covered by tests from day one.


⚙️ TDD Workflow Overview


Here’s the TDD cycle illustrated:


[Write Failing Test] → [Run Tests: Fails 🔴]

           ↓

     [Write Minimal Code]

           ↓

[Run Tests: Pass ✅] → [Refactor Code] → Repeat


🧩 Example: TDD in a Django Project


Let’s build a small Django feature using TDD —

for example, a To-Do app where users can create simple tasks.


🧱 Step 1: Write a Failing Test (RED)


Before writing any model or view, we start with a test that defines the behavior we want.


Create a test file tests/test_models.py:


from django.test import TestCase

from myapp.models import Task


class TaskModelTest(TestCase):


    def test_saving_and_retrieving_tasks(self):

        first_task = Task(title='Buy groceries')

        first_task.save()


        saved_tasks = Task.objects.all()

        self.assertEqual(saved_tasks.count(), 1)

        self.assertEqual(saved_tasks[0].title, 'Buy groceries')



Now run the test:


python manage.py test



❌ Output:


ImportError: cannot import name 'Task' from 'myapp.models'



Perfect — it fails because we haven’t created the Task model yet.

This is the RED stage.


🧩 Step 2: Write the Minimal Code (GREEN)


Now, let’s make the test pass by creating the minimal model.


models.py

from django.db import models


class Task(models.Model):

    title = models.CharField(max_length=200)



Run tests again:


python manage.py test



✅ Output:


.

----------------------------------------------------------------------

Ran 1 test in 0.002s


OK



The test passes!

We’re now in the GREEN stage.


🧩 Step 3: Refactor (REFACTOR)


At this stage, we can clean up or improve the code — for example, add __str__ or validations — without changing functionality.


class Task(models.Model):

    title = models.CharField(max_length=200)


    def __str__(self):

        return self.title



Re-run the tests to ensure nothing broke:


python manage.py test



✅ Still green — great!

That’s the REFACTOR stage.


🧩 Extending TDD to Views


Let’s now add a simple view that displays the list of tasks.


Step 1: Write a Failing Test (RED)

from django.test import TestCase

from django.urls import reverse

from myapp.models import Task


class TaskViewTest(TestCase):


    def test_displays_all_tasks(self):

        Task.objects.create(title='Task 1')

        Task.objects.create(title='Task 2')


        response = self.client.get(reverse('task_list'))

        self.assertContains(response, 'Task 1')

        self.assertContains(response, 'Task 2')



Run it:


python manage.py test



❌ It fails because the task_list view and URL don’t exist yet.


Step 2: Write Minimal Code (GREEN)

views.py

from django.shortcuts import render

from myapp.models import Task


def task_list(request):

    tasks = Task.objects.all()

    return render(request, 'task_list.html', {'tasks': tasks})


urls.py

from django.urls import path

from myapp import views


urlpatterns = [

    path('', views.task_list, name='task_list'),

]


Template: templates/task_list.html

<ul>

  {% for task in tasks %}

    <li>{{ task.title }}</li>

  {% endfor %}

</ul>



Run tests again:


python manage.py test



✅ All tests pass — you’ve implemented your feature completely through TDD!


🧩 Step 3: Refactor


Once all tests pass, you can safely improve your code:


Simplify queries.


Extract reusable components.


Improve templates.


Re-run tests to ensure everything still passes.


🧠 Benefits of TDD in Django

Benefit Description

Confidence Every feature is verified automatically.

Fewer bugs You catch mistakes before they reach production.

Cleaner design Forces you to think about what code should do before writing it.

Easy refactoring Safe to improve code since tests confirm correctness.

⚙️ Tools That Help with TDD


Django Test Client – simulates HTTP requests.


pytest-django – integrates Django with the simpler pytest framework.


coverage.py – checks how much of your code is tested.


Example:


coverage run manage.py test

coverage report -m


🧭 Summary: The TDD Cycle in Django

Step Action Goal

1. RED Write a failing test Define the expected behavior

2. GREEN Write minimal code to pass Implement the functionality

3. REFACTOR Clean and improve code Maintain readability and efficiency

Learn Fullstack Python Training in Hyderabad

Read More

Writing Unit Tests for Django Projects

Introduction to Unit Testing in Python

Testing and Debugging in Python

How to Test Your API Endpoints in Python

At Our Quality Thought Training Institute in Hyderabad

Get Directions

Subscribe by Email

Follow Updates Articles from This Blog via Email

No Comments

About

Search This Blog

Powered by Blogger.

Blog Archive