如何在Django测试POST接口时包含CSRF令牌?
我正在学习如何创建一个API接口,并且我想写一个测试,看看发送一个POST请求是否能返回200的状态码。我还打算写更多的测试,检查这个接口是否能返回所有预期的结果。不过,我总是得到403的状态码,我觉得这可能是因为我需要在POST数据中包含一个csrf令牌。请问在Django中测试一个POST接口的好方法是什么?
我的测试代码:
from django.test import TestCase
from app import settings
import requests
class ProjectEndpoint(TestCase):
def post_endpoint(self):
data = {'hello':'23'}
post_project = requests.post(settings.BASE_URL+'/api/project', params=data)
self.assertEqual(post_endpoint.status_code, 200)
这个测试总是失败,返回的是403而不是200。
我觉得这是因为这个视图是为了防止csrf攻击而受到保护,但我并不太确定。希望有人能给我一些建议。
1 个回答
其实,Django 默认情况下在测试时并不会强制进行 CSRF 检查,具体可以参考这个链接:https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#testing。
CsrfViewMiddleware 通常会给测试视图函数带来很大麻烦,因为每次发送 POST 请求时都需要带上 CSRF 令牌。为了这个原因,Django 的测试用 HTTP 客户端进行了修改,设置了一个标志,让请求可以放宽对中间件和 csrf_protect 装饰器的限制,这样它们就不会拒绝请求了。在其他方面(比如发送 cookies 等),它们的表现是一样的。
如果你出于某种原因想让测试客户端执行 CSRF 检查,你可以创建一个强制执行 CSRF 检查的测试客户端实例:
from django.test import Client
csrf_client = Client(enforce_csrf_checks=True)
不过,这要求你使用 Django 的客户端,而不是 requests;据我所知,Django 并没有模拟或处理 requests... 所以当你运行这个单元测试时,实际上是直接访问真实的服务器。
另外,请注意,你应该给你的测试函数命名时以 test_ 开头。
比如像这样(通过 django manage.py test .ProjectEndpoint 运行时):
def test_post_endpoint(self):
data = {'hello':'23'}
c = Client() #above, from django.test import TestCase,Client
#optional, but may be necessary for your configuration: c.login("username","password")
response = c.post('/api/project',params=data)
self.assertEqual(response.status_code, 200)