如何为带有IsAuthenticated权限的Django REST API端点编写单元测试
问题根因
reverse函数用法错误:reverse仅用于根据路由名称生成URL路径,仅接收路由定义的路径参数作为入参,你把登录请求的业务参数(邮箱、密码)传入reverse的kwargs中,自然找不到匹配的路由,触发NoReverseMatch报错。- model_bakery创建的用户密码为加密哈希值:直接读取
self.user.password拿到的是加密后的密文,无法作为明文密码请求登录接口。 - 认证前缀不匹配:SimpleJWT默认的认证前缀为
Bearer,你代码中使用的Token前缀会被认证中间件判定为无效。 - 冗余代码:自定义的
apiclient未被使用,属于无效代码。
解决方案
提供两种可选方案,可根据你的测试场景选择:
方案1:修正原有逻辑,完整走JWT认证流程
适合需要同时验证登录+业务接口的集成测试场景:
from rest_framework.test import APITestCase from model_bakery import baker from django.urls import reverse class TranslationTestCases(APITestCase): def setUp(self): self.role = baker.make(Roles) # 创建用户并手动设置明文可登录密码 self.user = baker.make(Users, user_role=self.role) self.test_pwd = "test_verify_123" self.user.set_password(self.test_pwd) self.user.save() self.translation = baker.make(Translation, _quantity=10) def test_get_all_translations(self): # 先请求token接口获取access凭证 token_url = reverse('token_obtain_pair') token_resp = self.client.post( token_url, data={"email": self.user.email, "password": self.test_pwd}, format="json" ) access_token = token_resp.data["access"] # 携带token请求目标接口,使用SimpleJWT默认的Bearer前缀 response = self.client.get( reverse('display_translation'), HTTP_AUTHORIZATION=f"Bearer {access_token}" ) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 10)
方案2:强制认证,跳过JWT申请流程(推荐单元测试使用)
如果仅需要测试翻译接口的业务逻辑,不需要校验登录流程,直接用DRF测试工具自带的强制认证方法即可,代码更简洁高效:
from rest_framework.test import APITestCase from model_bakery import baker from django.urls import reverse class TranslationTestCases(APITestCase): def setUp(self): self.role = baker.make(Roles) self.user = baker.make(Users, user_role=self.role) self.translation = baker.make(Translation, _quantity=10) # 直接给测试客户端绑定登录状态,无需请求token接口 self.client.force_authenticate(user=self.user) def test_get_all_translations(self): response = self.client.get(reverse('display_translation')) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 10)
内容的提问来源于stack exchange,提问作者Saad Mrabet
相关产品推荐
相关产品推荐

