Django DRF API 单元测试完整方案(基于 `TestCase`)

Django DRF API 单元测试完整方案(基于 TestCase

一、方案概述

使用 django.test.TestCaserest_framework.test.APIClient 进行 API 单元测试 ,确保 API 正确性、权限控制、数据返回格式、业务逻辑 等。


二、基本步骤

  1. 使用 setUp() 初始化测试环境

    • 创建 API 客户端 APIClient()
    • 预先插入数据库测试数据(如普通用户、管理员用户等)
    • 生成 Token 进行身份认证(如 TokenAuthentication
  2. 编写测试用例

    • 发送 GETPOSTPUTDELETE 请求
    • 断言 HTTP 状态码、数据格式、权限逻辑等
  3. 运行测试

    • 执行 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="test@example.com", password="password123")

        # 创建管理员用户
        self.admin_user = User.objects.create_superuser(username="admin", email="admin@example.com", 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 的稳定性

相关推荐
谭光志6 小时前
Vibe Coding 时代,程序员该何去何从
前端·后端·ai编程
GoGeekBaird7 小时前
我用 BeeWeave 跑完了一次完整写作闭环
后端·github
仿生狮子8 小时前
别再说“全栈”了,AI 时代团队只认这 5 种人
前端·人工智能·后端
Reart10 小时前
Leetcode 213.打家劫舍2(内含闲谈,打劫真是技术活,好题,716)
后端·算法
触底反弹11 小时前
🔥 RAG 到底是怎么工作的?掰开揉碎了给你讲明白!
javascript·人工智能·后端
techdashen11 小时前
Go 1.26 新增 `bytes.Buffer.Peek`:只看数据,不移动读取位置
开发语言·后端·golang
Reart11 小时前
Leetcode 198.打家劫舍(716)
后端·算法
Java编程爱好者12 小时前
Spring6.0+Boot3.0:秒级启动、万级并发的开发新姿势
后端
YYYing.12 小时前
【C++大型项目之高性能服务器框架 (七) 】Socket与ByteArray模块
服务器·c++·后端·框架·高性能·c/c++
青山木12 小时前
一把 Redis 分布式锁,踩透四个坑:锁争抢、僵尸锁、锁过期、锁丢失
java·数据库·redis·后端