在完全正常运行的django应用程序中测试POST时出现405错误

时间:2014-09-11 17:05:54

标签: python django post http-status-code-405

我在django中开发一个使用表单POST将用户输入的数据放入数据库的Web应用程序。

问题: 在django.test.TestCase中使用self.client.post()进行测试会返回405(不允许请求)。

规避:

  • 禁止POST - 应用程序在运行时成功发布(而不是运行tests.py时)。
  • CSRF问题 - django.test.TestCase在运行测试时默认禁用CSRF身份验证。
  • 一般的测试 - 我使用self.client.get()
  • 进行了多次测试

问题: 什么可能导致405,当我期望302(重定向)?

这是以这种方式失败的测试之一:

def test_process_one_match_in_title(self):
    #TODO: the server is refusing self.client.post requests in testing, although they work in the app proper.  Why?

    #create a user and an abstract
    this_abstract = Abstract.objects.get(pk=5)  #'hypoplasia' in both title and abstract text
    this_annotator = create_annotator("Joe")
    this_annotator.save()

    userMatchesJSON = "{'hypoplasia': 8}"

    resp = self.client.post(reverse('diseaseMatcherApp:abstractDetail', kwargs={'pk': this_abstract.id}),
                            {'inputSoFar': 'hypoplasia', 'abstract_pk': this_abstract.id, 'user.id': this_annotator.id,
                             'userMatches': userMatchesJSON})
    self.assertEqual(resp.status_code, 302)  #FAILS HERE; AssertionError: 405 != 302

2 个答案:

答案 0 :(得分:2)

这个问题让我很生气,这是搜索问题时出现的唯一问题。我不能说我有一个正确的解决方案,但我已经为我解决了,我想我可能会分享几个小时的调试结果。

我遇到了与你完全相同的问题,这是一个在单元测试中不起作用的POST请求,而在整个应用程序运行时它完全正常。在我的情况下甚至比较疯狂的是测试在我的笔记本电脑上工作但在我的台式机上没有,没有环境差异(相同的虚拟环境,只有python3.5.3 VS python3.5.1的细微差别)

我得到的信息是:

  • “方法不允许(POST):url / where / i / wanted / to / post”与测试方法名称隔行扫描(使用./manage.py test -v2运行时)
  • “测试总结”中的断言错误:“AssertionError:False不成立:响应未按预期重定向:响应代码为405(预期为302)”

使用以下代码:

r = self.client.post(url, follow=True)
self.assertRedirects(r, expected_url)

(我发布的URL由一个派生自CreateView的类处理)

第一条消息是从this piece of code开始的,该消息是通过this line

触发的
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)

...将request.method设置为'POST'...结果表明我的CreateView在测试模式下没有任何'post'方法(这很奇怪......显然在运行时)我的笔记本电脑视图有这个功能!),所以Django反而回到了'http_method_not_allowed'。

现在,为什么我的CreateView没有'POST'方法?我没有花时间去完成整个初始化过程(看起来相当复杂),所以我没有确切的想法,但事实证明,在我的测试中,有些URL在我的测试中根本没有“初始化”(我可以通过在urls/resolvers.py中的此函数中打印内容来弄清楚。例如,应该处理POST请求的URL我在运行测试时确实不存在...所以我想这就解释了为什么我的CreateView没有正确初始化

我终于发现我的问题来自于使用django-crudbuilder应用程序构建我的CRUD视图,并且当数据库为空时它没有正确初始化(在非持久性数据库上运行测试时就是这种情况) )

不确定在其他情况下该问题可能来自何处,但如果遇到此问题,您可能想要检查Django在运行测试时是否正确“看到”了所有网址(如果它们不是' t,试着找出原因。

(我链接的Django源代码来自当前的主代码,但它与我使用的版本1.11.7中的代码完全相同)

答案 1 :(得分:0)

我们遇到了同样的问题,正如 @theenglishway 所描述的那样。不幸的是,我们找不到问题的根源。但我们找到了一个对我们有用的解决方案。

解决方案

基本上,我们不再使用 django APIClient 中的 rest_framework.test,而是将其替换为 APIRequestFactory

from rest_framework.test import APIRequestFactory
from my_app.views import MyAPIsView


# Client for API Request Factory
request_factory = APIRequestFactory()

# Class based view that you want to test
view = MyAPIsView.as_view()

# Request object
request = request_factory.post('/your/post/endpoint/')

# Response obtained from request returned from view
response = view(request)