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 應用程式建立了測試。希望你喜歡這個教程。如果喜歡,請點擊下方的「喜歡」按鈕。如果你想要更多這樣的內容,請訂閱我的頻道,並記得點擊鈴鐺以獲取新影片的通知。下次視頻見!