在功能齐全的 django 应用程序中测试 POST 时出现 405 错误
Posted
技术标签:
【中文标题】在功能齐全的 django 应用程序中测试 POST 时出现 405 错误【英文标题】:405 error when testing POST in django application that is fully functional 【发布时间】:2014-11-05 17:53:28 【问题描述】:我正在 django 中开发一个 Web 应用程序,它使用表单 POST 将用户输入的数据放入数据库。
问题: 在 django.test.TestCase 中使用 self.client.post() 进行测试返回 405(不允许请求)。
排除:
POST 不允许 - 应用程序在运行时成功发布(而不是在运行 tests.py 时)。 CSRF 问题 - django.test.TestCase 在运行测试时默认禁用 CSRF 身份验证。 一般测试失败 - 我有几个使用 self.client.get() 可以正常工作的测试问题: 当我期望 302(重定向)时,可能导致 405 的原因是什么?
这是以这种方式失败的测试之一:
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
【问题讨论】:
你发帖的网址是什么? @ChrisHawkes 这是表单调用: 我只是好奇,因为您说一个应用程序在发布帖子时可以工作,而另一个则不能。我建议两者都发布到该网站的完整网址。 yoursite.com/post_form 可能是 url 是相对的,而不是完全限定的 url。 它实际上不是 2 个应用程序 - 它只是应用程序本身(通过浏览器体验)和该应用程序的测试套件(在 tests.py 中)。相同的页面,相同的表格。我猜在技术上不同的服务器 - 127.0.0.1:8000 与系统创建的 TestServer。但我不明白这是怎么回事,使用 reverse() 来解析 URL。 是的,我同意。我不太熟悉为什么测试服务器不能工作。我想知道这是否是浏览器问题,它没有让请求被发出,但我只是在猜测那里,希望有人解决了类似的问题并可以参与进来。 【参考方案1】:这个问题让我很生气,这是在搜索该问题时出现的关于该主题的唯一问题。我不能说我有一个适当的修复,但我已经为我解决了,我想我可能会分享几个小时的调试结果。
我遇到了与您完全相同的问题,即 POST 请求在单元测试中不起作用,而在整个应用程序运行时却完全正常。在我的情况下更疯狂的是,测试在我的笔记本电脑上运行,但在我的台式机上运行,没有环境差异(相同的虚拟环境,只有 python3.5.3 VS python3.5.1 的细微差别)
我收到的信息是:
“不允许的方法 (POST): url/where/i/wanted/to/post”与测试方法名称交错(使用 ./manage.py test -v2 运行时) “测试总结”中的断言错误:“AssertionError: False is not true : Response did not redirect as expected: Response code was 405 (expected 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 视图,并且当数据库为空时它没有正确初始化(在非持久性数据库上运行测试时就是这种情况)
不确定在其他情况下该问题可能来自哪里,但如果您遇到此问题,您可能希望在运行测试时检查您的所有 URL 是否被 Django 正确“看到”(如果它们不是) t,试着找出原因)。
(我链接的Django源代码来自当前的master,但它与我使用的版本1.11.7中的相同)
【讨论】:
【参考方案2】:我们遇到了同样的问题,正如 @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)
【讨论】:
以上是关于在功能齐全的 django 应用程序中测试 POST 时出现 405 错误的主要内容,如果未能解决你的问题,请参考以下文章