【问题标题】:Sending JSON using the django test client使用 django 测试客户端发送 JSON
【发布时间】:2012-01-24 21:06:27
【问题描述】:

我正在开发一个 django 项目,该项目将用作 webhook 的端点。 webhook 会将一些 JSON 数据发布到我的端点,然后它将解析该数据。我正在尝试为它编写单元测试,但我不确定我是否正确发送了 JSON。

我在 pipeline_endpoint 中不断收到“TypeError:字符串索引必须是整数”

代码如下:

# tests.py
from django.test import TestCase
from django.test.client import Client
import simplejson

class TestPipeline(TestCase):

    def setUp(self):
        """initialize the Django test client"""
        self.c = Client()

    def test_200(self):
        json_string = u'{"1": {"guid": "8a40135230f21bdb0130f21c255c0007", "portalId": 999, "email": "fake@email"}}'
        json_data = simplejson.loads(json_string)
        self.response = self.c.post('/pipeline-endpoint', json_data, content_type="application/json")
        self.assertEqual(self.response.status_code, "200")

# views.py
from pipeline.prospect import Prospect
import simplejson

def pipeline_endpoint(request):

    #get the data from the json object that came in
    prospects_json = simplejson.loads(request.raw_post_data)
    for p in prospects_json:
        prospect = {
            'email'          : p['email'],
            'hs_id'          : p['guid'],
            'portal'         : p['portalId'],
        }

编辑:整个回溯。

======================================================================
ERROR: test_200 (pipeline.tests.TestPipeline)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "F:\......\pipeline\tests.py", line 31, in test_200
    self.response = self.c.post('/pipeline-endpoint', json_string, content_type="application/json")
  File "C:\Python27\lib\site-packages\django\test\client.py", line 455, in post
    response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
  File "C:\Python27\lib\site-packages\django\test\client.py", line 256, in post
    return self.request(**r)
  File "C:\Python27\lib\site-packages\django\core\handlers\base.py", line 111, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "F:\......\pipeline\views.py", line 18, in pipeline_endpoint
    'email'          : p['email'],
TypeError: string indices must be integers

----------------------------------------------------------------------
Ran 1 test in 0.095s

FAILED (errors=1)
Destroying test database for alias 'default'...

【问题讨论】:

  • 是...因为您应该使用json.dumps(带有python对象)而不是json.loads(带有字符串),因此您通过python对象与您的客户端发送请求,而不是序列化为 json 对象的 python 对象?

标签: django json unit-testing


【解决方案1】:

@mrmagooey 是对的

def test_your_test(self):
    python_dict = {
        "1": {
            "guid": "8a40135230f21bdb0130f21c255c0007",
            "portalId": 999,
            "email": "fake@email"
        }
    }
    response = self.client.post('/pipeline-endpoint/',
                                json.dumps(python_dict),
                                content_type="application/json")

使用json.dumps 而不是json.loads

【讨论】:

    【解决方案2】:

    试试:

     self.client.generic('POST', '/url', json.dumps({'json': 'object'})
    

    【讨论】:

    • 也适用于“GET”!谢谢!
    • 请注意,client.generic() 是无证的,在这种情况下由client.post() 调用(或client.get()client.put() 等,用于其他请求方法)
    • 这个答案救了我两次。一次在 2019 年,另一次在 2014 年。
    • 如何在父类中写这个来为子类覆盖这个,这样这个json转换只写一次?
    【解决方案3】:

    rest_frameworkAPIClient(这是APITestCase 中的默认client_class)负责将dict 转储到JSON,并通过传递format='json' 设置正确的内容类型。

    from rest_framework import status
    from rest_framework.test import APIClient, APITestCase
    
    
    class MyTestCase(APITestCase):
        url = '/url'
    
        def post(self, payload, url=None):
            """
            Helper to send an HTTP post.
    
            @param (dict) payload: request body
    
            @returns: response
            """
            if url is None:
                url = self.url
    
            return self.client.post(url, payload, format='json')
    
        def test_my_function(self):
            payload = {
                'key': 'value'
            }
            response = self.post(payload)
            self.assertEqual(response.status_code, status.HTTP_200_OK)
    

    【讨论】:

      【解决方案4】:

      您始终可以使用加载原始请求数据的HttpRequest.body。这样您就可以处理自己的数据处理。

      c = Client()
      json_str= json.dumps({"data": {"id": 1}})
      c.post('/ajax/handler/', data= json_str, content_type='application/json',
                                               HTTP_X_REQUESTED_WITH='XMLHttpRequest')
      
      
      def index(request):
          ....
          print json.loads(request.body)
      

      【讨论】:

        【解决方案5】:

        从 Django 3.0 开始:

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

        response = client.post(
            f'/customer/{customer.id}/edit',
            {'email': new_email},
            content_type='application/json'
        )
        

        【讨论】:

          【解决方案6】:

          您可以在字典上使用iteritems 进行循环

          for index, p in prospects_json.iteritems():
            prospect={
              'email': p['email'],
            }
          

          或者

          for index in prospect_json:
            prospect={
              'email': prospect_json[ index ]['email']
            }
          

          【讨论】:

          • 感谢 iteritems() 提醒,但我仍然遇到 JSONDecodeError。 JSON 看起来很奇怪。
          • 不,实际上它在 shell 中运行良好。你能更新你的回溯吗?
          【解决方案7】:

          添加到 Guillaume Vincent 的回答中,从 Django 2.1 开始,我们不再需要使用 json.dumps 来传递数据。

          在 Django 2.1 中更改: 添加了上述 JSON 序列化。在旧版本中,您可以在将数据传递给 post() 之前对数据调用 json.dumps() 以实现相同的目的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-16
            • 2012-06-19
            • 1970-01-01
            • 2015-10-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多