如何在Django中测试POST端点时包含CSRF令牌?

36

我正在学习如何创建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个回答

44

实际上,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不会模拟/操作/等请求... 因此,当您运行该单元测试时,实际上会访问真实的服务器。

另外请注意,您应该将测试函数命名为以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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接