Django DRF APITestCase测试GET请求返回null无数据问题
DRF APITestCase接口测试返回b'null'问题解决方案
核心原因
self.client是Django测试框架内置的模拟客户端,不会发起真实网络请求访问你手动启动在localhost:5000的服务,而是直接在测试进程内加载Django配置、走内存级请求链路,和你浏览器访问的运行中服务是完全隔离的两个环境。返回b'null'说明请求链路最终返回的JSON序列化结果是null,通常由以下几个问题导致:
- 测试环境使用独立的空测试数据库,和你开发用的数据库完全隔离,没有提前创建测试数据的话,视图查询不到结果,异常分支返回
None,经JsonResponse序列化后就是null - 测试环境路由配置错误,
/api/v1/rest_of_url/路径绑定的不是你预期的业务视图 - 视图有权限校验逻辑,测试客户端默认是匿名未登录状态,校验未通过时没有返回403错误,反而返回了
None - 视图直接返回Django原生
JsonResponse而非DRF的Response对象,这种响应对象没有data属性,直接访问会抛错
修复步骤
- 测试方法内提前构造测试数据,不要依赖开发库的存量数据
from rest_framework.test import APITestCase from rest_framework import status from yourapp.models import StuffModel # 替换成你的业务模型 from django.contrib.auth.models import User class TargetApiTestCase(APITestCase): def test_get(self): # 接口需要登录的话先构造用户并认证 test_user = User.objects.create_user(username="test", password="testpass123") self.client.force_authenticate(user=test_user) # 构造接口需要的业务测试数据 StuffModel.objects.create(stuff=3, stuff2="adf", stuff3="asdf", stuff4="ff") # 发起请求 response = self.client.get("/api/v1/rest_of_url/", format="json") # 先断言状态码符合预期 self.assertEqual(response.status_code, status.HTTP_200_OK) # 原生JsonResponse用.json()方法获取解析后的字典,不要访问.data resp_data = response.json() print(resp_data) # 编写业务断言 self.assertEqual(resp_data["count"], 1) self.assertEqual(len(resp_data["results"]), 1) self.assertEqual(resp_data["results"][0]["stuff"], 3)
- 校验测试环境路由配置
确认项目配置文件中,测试场景下的ROOT_URLCONF指向项目主路由文件,/api/v1/rest_of_url/路径绑定的视图和你浏览器访问的视图完全一致,避免路由错配导致请求走到了返回空值的其他逻辑里。 - 排查视图分支逻辑
检查视图中是否有针对认证状态、请求头、运行环境的特殊判断,避免匿名请求、测试环境请求走到返回None的异常分支。所有异常分支应该返回明确的状态码和错误信息,不要隐式返回空值。 - (不推荐)如果要直接测试已经启动在5000端口的运行中服务,不要使用测试客户端,改用
requests库发起真实HTTP请求即可。注意这种方式依赖外部服务状态,不适合作为单元测试方案。
内容的提问来源于stack exchange,提问作者Matteo Possamai
相关产品推荐
相关产品推荐

