Django REST Framework接口测试失败:test_create_post断言错误
问题场景
编写接口测试时,test_create_post用例持续失败,返回400状态码,预期结果为201。
测试代码(test.py)
from rest_framework.test import APITestCase, APIRequestFactory from rest_framework import status from django.urls import reverse from .views import PostViewSet from django.contrib.auth import get_user_model User = get_user_model() class PostListCreateTestCase(APITestCase): def setUp(self): self.factory = APIRequestFactory() self.view = PostViewSet.as_view({"get": "list", "post": "create"}) self.url = reverse("post_list") self.user = User.objects.create( email="testuser@gmail.com", name="testuser", password="pass" ) def test_list_posts(self): request = self.factory.get(self.url) response = self.view(request) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_create_post(self): sample_post = { "title": "sample title", "body": "sample body", } request = self.factory.post(self.url, sample_post) request.user = self.user response = self.view(request) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
视图代码
from rest_framework import viewsets, status from rest_framework.response import Response from django.shortcuts import get_object_or_404 from .serializers import PostSerializer, LikeSerializer from .models import Post, Like class PostViewSet(viewsets.ModelViewSet): serializer_class = PostSerializer queryset = Post.objects.all() def get_queryset(self): posts = Post.objects.all() return posts def get_object(self): post = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"]) self.check_object_permissions(self.request, post) return post def create(self, request, *args, **kwargs): try: post = Post.objects.create( title=request.data.get("title"), body=request.data.get("body"), author=request.user, ) post = PostSerializer(post) return Response(post.data, status=status.HTTP_201_CREATED) except Exception as ex: return Response(str(ex), status=status.HTTP_400_BAD_REQUEST) def list(self, request, *args, **kwargs): posts = self.get_queryset() serializer = self.get_serializer(posts, many=True) return Response( data=dict(posts=serializer.data, total=len(serializer.data)), status=status.HTTP_200_OK, )
测试结果
Found 2 test(s). Creating test database for alias 'default'... System
check identified no issues (0 silenced). F.
====================================================================== FAIL: test_create_post (posts.tests.PostListCreateTestCase)
---------------------------------------------------------------------- Traceback (most recent call last): File
"/home/amr/Snakat/social_network/posts/tests.py", line 31, in
test_create_post
self.assertEqual(response.status_code, status.HTTP_201_CREATED) AssertionError: 400 != 201---------------------------------------------------------------------- Ran 2 tests in 0.023s
FAILED (failures=1) Destroying test database for alias 'default'...
排查与修复步骤
1. 先获取具体错误信息
视图的create方法捕获所有异常并返回字符串,但测试代码未输出错误详情。修改测试用例添加打印语句:
def test_create_post(self): sample_post = { "title": "sample title", "body": "sample body", } request = self.factory.post(self.url, sample_post) request.user = self.user response = self.view(request) print("错误详情:", response.data) # 新增此行 self.assertEqual(response.status_code, status.HTTP_201_CREATED)
运行测试后即可看到具体错误原因,比如用户创建问题、字段约束问题等。
2. 修复用户创建方式
直接用User.objects.create设置密码会存储明文,不符合Django用户模型规范,应改用create_user方法,该方法会自动哈希密码并确保字段验证通过:
# 在setUp方法中修改用户创建代码 self.user = User.objects.create_user( email="testuser@gmail.com", name="testuser", password="pass" )
3. 规范视图的create方法(可选但推荐)
当前视图直接创建数据库对象,跳过了序列化器的验证逻辑,容易忽略数据合法性问题。改用DRF标准的序列化器验证流程:
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 将当前用户作为author传入 serializer.save(author=request.user) return Response(serializer.data, status=status.HTTP_201_CREATED)
此方式不仅能自动处理数据验证,还能返回结构化的错误信息,方便调试。
4. 检查请求内容类型(若需要)
如果视图期望接收JSON格式数据,需在构造请求时指定content_type:
import json # 在test_create_post中修改请求构造代码 request = self.factory.post( self.url, json.dumps(sample_post), content_type='application/json' )
内容的提问来源于stack exchange,提问作者Raskolnikov

