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

Django TDD 實戰教學:測試驅動開發CRUD應用程式

Summary

Language:

Quick Abstract

想知道如何在 Django 中進行測試嗎?這個影片將教你使用測試驅動開發(TDD)方法,從零開始建立一個簡單的 CRUD 應用程式。TDD 是一種先寫測試再寫程式的開發模式,能確保程式碼的品質與可靠性。雖然一開始可能覺得奇怪或冗餘,但你會發現 TDD 能夠幫助你寫出更好的程式碼,並減少錯誤。

Quick Takeaways:

  • 學習 TDD 的基本概念,先寫測試再開發。

  • 建立 Django 專案和應用程式,並設定測試環境。

  • 測試 Django 模型是否存在,以及資料庫是否為空。

  • 建立模型字串表示測試,確保回傳正確標題。

  • 測試網頁是否使用正確的模板和 HTTP 狀態碼。

  • 測試表單是否有效,以及表單提交後的重新導向是否正確。

  • 測試新增、更新和刪除功能。

影片將涵蓋模型、模板、表單和視圖的測試,並逐步引導您完成整個過程。透過實作,你會了解如何使用 Django 測試工具,確保你的應用程式在開發過程中保持高品質。

TDD 介紹

在本影片中,我將在建立一個簡單的 CRUD 應用程式時,教你 Django 中的測試基礎。我們要學習的測試形式稱為 TDD(測試驅動開發)。這意味著在開始編寫程式碼之前,我們先撰寫測試。

這可能聽起來有點奇怪,一開始也可能會有這種感覺。它也可能讓人覺得冗餘和緩慢,但我可以向你保證,如果你嘗試一下,你會喜歡上它。TDD 非常受歡迎,它確保你的程式碼運行得更好。這種形式的測試也使編寫更好的程式碼變得更容易,因為在開始構建之前,你實際上必須描述問題。

建立 Django 專案和應用程式

首先,確保已安裝 Django。然後在終端機中執行以下命令建立新的專案:

django - admin startproject tdd_testing

進入專案目錄:

cd tdd_testing

接著建立一個名為 task 的應用程式:

python manage.py startapp task

settings.py 中註冊 task 應用程式。

開始測試

測試模型是否存在

task 應用程式的 tests.py 中,建立一個測試類 TaskModelTest 來測試是否存在 Task 的 Django 模型,以及資料庫中是否沒有任務(預設情況)。

from django.test import TestCase
from.models import Task

class TaskModelTest(TestCase):
    def test_task_model_exists(self):
        tasks = Task.objects.count()
        self.assertEqual(tasks, 0)

執行測試:

python manage.py test

如果出現 name 'Task' is not defined 錯誤,則導入 Task 模型。如果出現 you can't import Task from task.models 錯誤,則建立 Task 模型。

建立 Task 模型

models.py 中建立 Task 模型:

from django.db import models

class Task(models.Model):
    title = models.CharField(max_length=255)
    description = models.TextField(blank=True, null=True)

執行遷移:

python manage.py make migrations
python manage.py migrate

再次執行測試,確保一切正常。

測試模型的字串表示

tests.py 中,為 Task 模型的字串表示建立一個測試:

def test_model_has_string_representation(self):
    task = Task.objects.create(title='First task')
    self.assertEqual(str(task), task.title)

如果測試失敗,則在 models.py 中更新 Task 模型的 __str__ 方法:

def __str__(self):
    return self.title

更新測試以確保字串表示正確。

測試頁面

測試索引頁

tests.py 中建立一個新的測試類 IndexPageTest 來測試索引頁:

class IndexPageTest(TestCase):
    def test_index_page_returns_correct_response(self):
        response = self.client.get('/')
        self.assertTemplateUsed(response, 'task/index.html')
        self.assertEqual(response.status_code, 200)

如果測試失敗,則在 views.py 中建立索引頁視圖:

from django.shortcuts import render

def index(request):
    return render(request, 'task/index.html')

task 應用程式的 urls.py 中配置索引頁的 URL 模式,並在主 urls.py 中包含 task 應用程式的 URL。

建立索引頁模板

task 應用程式的 templates 目錄下建立 task 子目錄,並在其中建立 index.html 模板。

測試索引頁是否列出任務

tests.py 中為索引頁列出任務建立一個測試:

def test_index_page_has_tasks(self):
    response = self.client.get('/')
    task = Task.objects.create(title='First task')
    self.assertContains(response, task.title)

如果測試失敗,則在 views.py 中更新索引頁視圖以獲取任務並傳遞給模板。在 index.html 模板中列出任務。

測試詳細頁

建立詳細頁測試

tests.py 中建立一個新的測試類 DetailPageTest 來測試詳細頁:

class DetailPageTest(TestCase):
    def setUp(self):
        self.task = Task.objects.create(title='First task', description='Description')

    def test_detail_page_returns_correct_response(self):
        response = self.client.get(f'/task/{self.task.id}/')
        self.assertTemplateUsed(response, 'task/detail.html')
        self.assertEqual(response.status_code, 200)

如果測試失敗,則在 views.py 中建立詳細頁視圖:

def detail(request, primary_key):
    task = Task.objects.get(pk=primary_key)
    return render(request, 'task/detail.html', {'task': task})

task 應用程式的 urls.py 中配置詳細頁的 URL 模式。

建立詳細頁模板

task 應用程式的 templates 目錄下的 task 子目錄中建立 detail.html 模板。

測試詳細頁內容

tests.py 中為詳細頁的內容建立測試:

def test_detail_page_has_correct_content(self):
    response = self.client.get(f'/task/{self.task.id}/')
    self.assertContains(response, self.task.title)
    self.assertContains(response, self.task.description)

確保詳細頁模板顯示任務的標題和描述。

測試新頁面

建立新頁面測試

tests.py 中建立一個新的測試類 NewPageTest 來測試新頁面:

class NewPageTest(TestCase):
    def test_new_page_returns_correct_response(self):
        response = self.client.get('/new/')
        self.assertTemplateUsed(response, 'task/new.html')
        self.assertEqual(response.status_code, 200)

如果測試失敗,則在 views.py 中建立新頁面視圖:

def new(request):
    return render(request, 'task/new.html')

task 應用程式的 urls.py 中配置新頁面的 URL 模式。

建立新頁面模板

task 應用程式的 templates 目錄下的 task 子目錄中建立 new.html 模板。

測試表單

建立表單

task 應用程式中建立 forms.py 文件,並建立 NewTaskForm 表單:

from django import forms
from.models import Task

class NewTaskForm(forms.ModelForm):
    class Meta:
        model = Task
        fields = ['title', 'description']

測試表單

tests.py 中為表單建立測試:

from.forms import NewTaskForm

class NewPageTest(TestCase):
    def setUp(self):
        self.form = NewTaskForm()

    def test_form_can_be_valid(self):
        self.assertTrue(issubclass(self.form.__class__, NewTaskForm))
        self.assertTrue('title' in self.form.Meta.fields)
        self.assertTrue('description' in self.form.Meta.fields)

        form = self.form(data={'title': 'Title', 'description': 'Description'})
        self.assertTrue(form.is_valid())

測試新頁面是否包含表單

tests.py 中為新頁面包含表單建立測試:

def test_new_page_form_rendering(self):
    response = self.client.get('/new/')
    self.assertContains(response, '<form')
    self.assertContains(response, 'csrfmiddlewaretoken')
    self.assertContains(response, '<label')

如果測試失敗,則在 new.html 模板中添加表單。

測試表單提交

tests.py 中為表單提交建立測試:

def test_new_page_invalid_form(self):
    response = self.client.post('/new/', {'description': 'Description'})
    self.assertContains(response, '<ul class="errorlist">')
    self.assertContains(response, 'This field is required.')

views.py 中處理表單提交。

測試有效表單提交

tests.py 中為有效表單提交建立測試:

def test_valid_form(self):
    response = self.client.post('/new/', {'title': 'New task', 'description': 'Description'})
    self.assertRedirects(response, '/')
    self.assertEqual(Task.objects.count(), 1)

views.py 中處理有效表單提交並重定向到索引頁。

測試更新頁面

建立更新頁面測試

tests.py 中建立一個新的測試類 UpdatePageTest 來測試更新頁面:

class UpdatePageTest(TestCase):
    def setUp(self):
        self.task = Task.objects.create(title='First task')

    def test_update_page_returns_correct_response(self):
        response = self.client.get(f'/update/{self.task.id}/')
        self.assertTemplateUsed(response, 'task/update.html')
        self.assertEqual(response.status_code, 200)

如果測試失敗,則在 views.py 中建立更新頁面視圖:

def update(request, primary_key):
    task = Task.objects.get(pk=primary_key)
    return render(request, 'task/update.html', {'task': task})

task 應用程式的 urls.py 中配置更新頁面的 URL 模式。

建立更新頁面模板

task 應用程式的 templates 目錄下的 task 子目錄中建立 update.html 模板。

測試更新表單

forms.py 中建立 UpdateTaskForm 表單:

class UpdateTaskForm(forms.ModelForm):
    class Meta:
        model = Task
        fields = ['title', 'description']

tests.py 中為更新表單建立測試:

from.forms import UpdateTaskForm

class UpdatePageTest(TestCase):
    def setUp(self):
        self.task = Task.objects.create(title='First task')
        self.form = UpdateTaskForm(instance=self.task)

    def test_form_can_be_valid(self):
        form = self.form(data={'title': 'New title', 'description': 'New description'})
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(self.task.title, 'New title')

    def test_form_can_be_invalid(self):
        form = UpdateTaskForm(instance=self.task, data={'title': ''})
        self.assertFalse(form.is_valid())

views.py 中處理更新表單提交。

測試更新頁面表單渲染和提交

tests.py 中為更新頁面表單渲染和提交建立測試:

def test_update_page_form_rendering(self):
    response = self.client.get(f'/update/{self.task.id}/')
    self.assertContains(response, '<form')
    self.assertContains(response, 'csrfmiddlewaretoken')
    self.assertContains(response, '<label')

def test_update_page_invalid_form(self):
    response = self.client.post(f'/update/{self.task.id}/', {'description': 'Description'}, instance=self.task)
    self.assertContains(response, '<ul class="errorlist">')
    self.assertContains(response, 'This field is required.')

def test_valid_update_form(self):
    response = self.client.post(f'/update/{self.task.id}/', {'title': 'Updated task', 'description': 'Updated description'}, instance=self.task)
    self.assertRedirects(response, '/')
    self.assertEqual(Task.objects.count(), 1)

views.py 中處理更新頁面表單提交並重定向到索引頁。

測試刪除頁面

建立刪除頁面測試

tests.py 中建立一個新的測試類 DeletePageTest 來測試刪除頁面:

class DeletePageTest(TestCase):
    def setUp(self):
        self.task = Task.objects.create(title='First task')

    def test_delete_page_actually_delete_a_task(self):
        self.assertEqual(Task.objects.count(), 1)
        response = self.client.get(f'/delete/{self.task.id}/')
        self.assertRedirects(response, '/')
        self.assertEqual(Task.objects.count(), 0)

如果測試失敗,則在 views.py 中建立刪除頁面視圖:

def delete(request, primary_key):
    task = Task.objects.get(pk=primary_key)
    task.delete()
    return redirect('/')

task 應用程式的 urls.py 中配置刪除頁面的 URL 模式。

結束

現在我們已經為 Django 中的完整 CRUD 應用程式建立了測試。希望你喜歡這個教程。如果喜歡,請點擊下方的「喜歡」按鈕。如果你想要更多這樣的內容,請訂閱我的頻道,並記得點擊鈴鐺以獲取新影片的通知。下次視頻見!

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.