当pytest与REST框架交互时,PATCH和PUT不能按预期工作

时间:2016-10-06 23:06:57

标签: python django-rest-framework put pytest-django

我正在使用django REST框架构建API。

为了测试这个API我正在使用pytest和测试客户端,如下所示:

def test_doesnt_find(self, client):
    resp = client.post(self.url, data={'name': '123'})
    assert resp.status_code == 404

def test_doesnt_find(self, client):
    resp = client.get(self.url, data={'name': '123'})
    assert resp.status_code == 404

在使用REST框架的常规GET,POST和DELETE类(如DestroyAPIViewRetrieveUpdateAPIView或仅APIView使用get和post函数)时都能正常工作

我遇到问题的地方是使用PATCH和PUT视图。例如RetrieveUpdateAPIView。在这里,我突然不得不使用:

resp = client.patch(self.url, data="name=123", content_type='application/x-www-form-urlencoded')

resp = client.patch(self.url, data=json.dumps({'name': '123'}), content_type='application/json')

如果我只是像我习惯的那样尝试使用测试客户端,我会收到错误:

rest_framework.exceptions.UnsupportedMediaType: Unsupported media type "application/octet-stream" in request.

当我指定' application / json'在client.patch()调用:

rest_framework.exceptions.ParseError: JSON parse error - Expecting property name enclosed in double quotes: line 1 column 2 (char 1)`

任何人都可以向我解释这种行为吗?特别难以捕捉,因为curl使用-X PATCH -d"name=123"也能正常工作。

3 个答案:

答案 0 :(得分:7)

  

rest_framework.exceptions.ParseError:JSON解析错误 - 期望用双引号括起来的属性名:第1行第2列(char 1)`

这通常表示您在json中的字符串中发送字符串。 例如:

resp = client.patch(self.url, data=json.dumps("name=123"), content_type='application/json')

会导致这类问题。

  

rest_framework.exceptions.UnsupportedMediaType:不支持的媒体类型" application / octet-stream"在请求中。

这意味着该请求已被发送为" application / octet-stream"这是Django的测试默认值。

为了通过处理所有这些来缓解痛苦,Django REST框架自己提供了一个客户端:http://www.django-rest-framework.org/api-guide/testing/#apiclient

请注意,语法与Django的语法略有不同,您不必处理json编码。

答案 1 :(得分:0)

Pytest使用django测试客户端,client.post的默认content_type是 multipart / form-data ,而putpatchdelete使用 application / octet-stream

这就是有时候这很棘手的原因。即使发布请求,如果您计划支持JSON有效负载,也必须在测试请求中告知内容类型。无论如何,在最新的Django版本中,您只需将数据对象传递给客户端请求,即可为您序列化,如docs中所声明:

如果您提供content_type作为application / json,则数据为 如果是字典,列表或元组,请使用json.dumps()进行序列化。 默认情况下,序列化是使用DjangoJSONEncoder执行的,并且可以 通过向客户端提供json_encoder参数来覆盖此属性。这个 序列化也会发生在put(),patch()和delete()请求上。

例如:

resp = client.patch(self.url, {'name': '123'}, content_type='application/json')

答案 2 :(得分:-1)

对于使用JSON数据的请求,由于JSON syntax字符串需要双引号,因此您收到此错误。