Django DRF API 單元測試完整方案(基于 TestCase
)
一、方案概述
使用 django.test.TestCase
和 rest_framework.test.APIClient
進行 API 單元測試,確保 API 正確性、權限控制、數據返回格式、業務邏輯 等。
二、基本步驟
-
使用
setUp()
初始化測試環境- 創建 API 客戶端
APIClient()
- 預先插入數據庫測試數據(如普通用戶、管理員用戶等)
- 生成
Token
進行身份認證(如TokenAuthentication
)
- 創建 API 客戶端
-
編寫測試用例
- 發送
GET
、POST
、PUT
、DELETE
請求 - 斷言 HTTP 狀態碼、數據格式、權限邏輯等
- 發送
-
運行測試
- 執行
python manage.py test
運行測試
- 執行
三、測試場景 1:權限控制(用戶管理 API)
HTTP 方法 | 端點 | 功能描述 |
---|---|---|
POST | /api/users/ | 創建用戶 |
GET | /api/users/ | 獲取用戶列表(需要身份認證) |
GET | /api/users/{id}/ | 獲取用戶詳情(僅管理員可查看) |
PUT | /api/users/{id}/ | 更新用戶信息(僅限用戶本人) |
DELETE | /api/users/{id}/ | 刪除用戶(僅管理員可刪除) |
完整的 API 測試代碼
from django.test import TestCase
from rest_framework.test import APIClient
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Tokenclass UserAPITestCase(TestCase):"""用戶 API 測試"""def setUp(self):"""初始化 API 客戶端,并創建測試用戶和管理員"""self.client = APIClient()# 創建普通用戶self.user = User.objects.create_user(username="testuser", email="test@example.com", password="password123")# 創建管理員用戶self.admin_user = User.objects.create_superuser(username="admin", email="admin@example.com", password="adminpass")# 生成 Tokenself.token, _ = Token.objects.get_or_create(user=self.user)self.admin_token, _ = Token.objects.get_or_create(user=self.admin_user)def test_get_users_without_authentication(self):"""測試未登錄獲取用戶列表,應該返回 403"""response = self.client.get("/api/users/")self.assertEqual(response.status_code, 403)def test_get_users_with_authentication(self):"""測試登錄后獲取用戶列表"""self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")response = self.client.get("/api/users/")self.assertEqual(response.status_code, 200)
四、測試場景 2:API 依賴前置 setUp()
(菜品管理 API)
HTTP 方法 | 端點 | 功能描述 |
---|---|---|
POST | /api/categories/ | 創建菜品分類 |
GET | /api/categories/ | 獲取菜品分類列表 |
POST | /api/dishes/ | 創建菜品(必須指定已有的菜品分類) |
GET | /api/dishes/ | 獲取菜品列表 |
完整的 API 測試代碼
from django.test import TestCase
from rest_framework.test import APIClient
from myapp.models import Category, Dishclass DishAPITestCase(TestCase):"""菜品 API 測試"""def setUp(self):"""初始化 API 客戶端,并創建測試數據"""self.client = APIClient()# 創建一個分類self.category = Category.objects.create(name="熱菜")def test_create_dish_with_valid_category(self):"""測試創建菜品(分類有效)"""data = {"name": "宮保雞丁", "price": "25.00", "category": self.category.id}response = self.client.post("/api/dishes/", data, format="json")self.assertEqual(response.status_code, 201)self.assertEqual(response.data["name"], "宮保雞丁")def test_create_dish_with_invalid_category(self):"""測試創建菜品(分類不存在)"""data = {"name": "魚香肉絲", "price": "22.00", "category": 999} # 不存在的分類 IDresponse = self.client.post("/api/dishes/", data, format="json")self.assertEqual(response.status_code, 400)self.assertIn("分類不存在", response.data["category"])
五、運行測試
python manage.py test myapp
六、方案總結
功能 | 方法 | 斷言 |
---|---|---|
獲取用戶列表(未登錄) | test_get_users_without_authentication() | self.assertEqual(response.status_code, 403) |
獲取用戶列表(已登錄) | test_get_users_with_authentication() | self.assertEqual(response.status_code, 200) |
創建菜品(分類有效) | test_create_dish_with_valid_category() | self.assertEqual(response.status_code, 201) |
創建菜品(分類不存在) | test_create_dish_with_invalid_category() | self.assertEqual(response.status_code, 400) |
? 覆蓋了權限控制 + API 依賴數據,確保 Django DRF API 的穩定性