如何为Django中返回JSON数据的视图创建单元测试
Django JSON列表视图单元测试实现方案
这类直接返回模型全量字段JSON列表的视图,测试核心覆盖三个维度即可:视图可正常访问、响应格式符合JSON要求、返回内容和数据库存储数据完全一致。如果项目中存在大量同类型视图,可以抽取公共测试基类减少重复代码。
单视图基础测试写法
使用Django内置的测试框架就能完成,不需要额外引入第三方依赖,基础测试代码示例如下:
from django.test import TestCase, Client from .models import Us import json class TestUserJsonListView(TestCase): def setUp(self): # 测试前置初始化:创建测试客户端、构造测试数据、配置目标路由 self.client = Client() self.user1 = Us.objects.create(name="张三", age=20, email="zhangsan@test.com") self.user2 = Us.objects.create(name="李四", age=22, email="lisi@test.com") self.target_url = "/your/actual/json_list_user/route/" # 替换为视图绑定的真实路由 def test_view_access_normal(self): # 校验视图可正常访问,响应格式正确 resp = self.client.get(self.target_url) self.assertEqual(resp.status_code, 200) self.assertEqual(resp["Content-Type"], "application/json") def test_response_data_match_db(self): # 校验返回的JSON内容和数据库数据一致 resp = self.client.get(self.target_url) resp_data = json.loads(resp.content) # 先校验返回数据条数 self.assertEqual(len(resp_data), Us.objects.count()) # 逐字段校验内容 self.assertEqual(resp_data[0]["id"], self.user1.id) self.assertEqual(resp_data[0]["name"], self.user1.name) self.assertEqual(resp_data[0]["age"], self.user1.age) self.assertEqual(resp_data[0]["email"], self.user1.email) self.assertEqual(resp_data[1]["id"], self.user2.id) self.assertEqual(resp_data[1]["name"], self.user2.name) self.assertEqual(resp_data[1]["age"], self.user2.age) self.assertEqual(resp_data[1]["email"], self.user2.email)
多同类型视图复用方案
针对多个结构相同的JSON列表视图,可以抽取公共测试基类,新增视图时只需要配置3个基础参数就能完成全量基础测试,不需要重复写校验逻辑:
from django.test import TestCase, Client import json class BaseJsonListTestCase(TestCase): # 子类需要覆盖以下三个配置项 view_route = None related_model = None test_dataset = [] def setUp(self): self.client = Client() # 批量构造测试数据 self.created_records = [] for item in self.test_dataset: obj = self.related_model.objects.create(**item) self.created_records.append(obj) def test_base_access_and_format(self): # 公共校验:访问状态码、响应格式 self.assertIsNotNone(self.view_route, "请配置视图对应的路由地址") self.assertIsNotNone(self.related_model, "请配置视图关联的模型类") resp = self.client.get(self.view_route) self.assertEqual(resp.status_code, 200) self.assertEqual(resp["Content-Type"], "application/json") def test_data_consistency(self): # 公共校验:返回数据和数据库一致 resp = self.client.get(self.view_route) resp_data = json.loads(resp.content) self.assertEqual(len(resp_data), self.related_model.objects.count()) # 逐字段对比,自动处理时间类字段的序列化格式差异 for idx, record in enumerate(self.created_records): db_record = self.related_model.objects.filter(id=record.id).values().first() for key, val in db_record.items(): if hasattr(val, "isoformat"): serialized_val = val.isoformat().replace("+00:00", "Z") if "T" in val.isoformat() else val.isoformat() self.assertEqual(resp_data[idx][key], serialized_val) else: self.assertEqual(resp_data[idx][key], val) # 新增同类型视图的测试只需要以下几行代码 class TestUserListView(BaseJsonListTestCase): view_route = "/api/user/list/" related_model = Us test_dataset = [ {"name": "张三", "age": 20, "email": "zhangsan@test.com"}, {"name": "李四", "age": 22, "email": "lisi@test.com"} ] # 比如其他商品列表、分类列表的JSON视图,直接继承基类配置即可 class TestGoodsListView(BaseJsonListTestCase): view_route = "/api/goods/list/" related_model = Goods test_dataset = [ {"goods_name": "矿泉水", "price": 2, "stock": 1000}, {"goods_name": "可乐", "price": 3.5, "stock": 500} ]
注意事项
- 如果视图配置了登录、权限校验逻辑,在
setUp方法里提前完成测试用户登录,或是给测试请求加上合法的认证头即可,不需要改动核心测试逻辑 - 如果视图支持筛选、分页、排序参数,只需要在对应视图的测试类里补充单独的测试方法,传入不同参数校验返回结果即可,基础的访问、格式、全量数据校验逻辑直接复用基类
- 示例视图里
JsonResponse传入了safe=False参数,允许返回非字典类型的JSON结构,测试时不需要强制校验响应根节点为字典,只要可以正常被JSON解析、数据和数据库存储内容匹配就符合预期 - Django测试框架运行用例时会自动创建隔离的测试数据库,所有测试过程中生成的测试数据都会在用例跑完后自动清除,不会污染开发、生产环境的业务数据
内容的提问来源于stack exchange,提问作者Ivan Campelo
相关产品推荐
相关产品推荐

