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 测试代码
python
from django.test import TestCase
from rest_framework.test import APIClient
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
class UserAPITestCase(TestCase):
"""用户 API 测试"""
def setUp(self):
"""初始化 API 客户端,并创建测试用户和管理员"""
self.client = APIClient()
# 创建普通用户
self.user = User.objects.create_user(username="testuser", email="[email protected]", password="password123")
# 创建管理员用户
self.admin_user = User.objects.create_superuser(username="admin", email="[email protected]", password="adminpass")
# 生成 Token
self.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 测试代码
python
from django.test import TestCase
from rest_framework.test import APIClient
from myapp.models import Category, Dish
class 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} # 不存在的分类 ID
response = self.client.post("/api/dishes/", data, format="json")
self.assertEqual(response.status_code, 400)
self.assertIn("分类不存在", response.data["category"])
五、运行测试
bash
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 的稳定性