如何在单元测试中使用JSON发送请求

116

我在一个Flask应用程序中编写了代码,使用JSON格式的请求,可以像这样获取JSON对象:

Request = request.get_json()

目前这个功能运作良好,但我想使用Python的unittest模块创建单元测试,而我很难找到一种方法来发送包含JSON的请求。

response=self.app.post('/test_function', 
                       data=json.dumps(dict(foo = 'bar')))

这给了我:

>>> request.get_data()
'{"foo": "bar"}'
>>> request.get_json()
None

Flask似乎有一个JSON参数,您可以在POST请求中设置json = dict(foo ='bar'),但我不知道如何使用unittest模块实现。


request.data 包含什么内容?通常当 JSON 解析由于错误的输入而失败时,它会默默地失败并返回 None,因此原始输入数据可能不是 JSON。 - Benoît Latinier
request.get_data() '{"foo": "bar"}' request.get_json() None
我不太确定 Flask 的请求是如何工作的,但它似乎将数据和 JSON 分开处理。如果有意义的话,我无法弄清楚如何将信息发送到 JSON 而不是数据。
- Sepehr Nazari
9
我认为这是内容类型头的问题,尝试将它们设置为application/json。另外,force参数很有帮助,但你可能不想去那里只是为了让单元测试通过,最好改变mime类型。 - user3012759
2个回答

222

将帖子更改为

response=self.app.post('/test_function', 
                       data=json.dumps(dict(foo='bar')),
                       content_type='application/json')

问题已解决。

感谢user3012759的帮助。


我一直在为这个问题苦恼。不明白为什么在已经指定了“application/json”内容类型的情况下还需要转储数据。 - dimmg
我认为这是因为在post请求中发送的所有内容都必须是字符串。 - Sepehr Nazari
23
太神奇了,因为Flask的test_client没有API文档!这不应该在文档中吗? - rjurney
1
如何从响应中获取数据? - variable
2
通过像 resp = client.post('/my/endpoint/',json=my_json_data) 这样的 post 请求响应,您可以使用 resp.data 访问数据字节,并在 @variable 中使用它。 - amiabl
要小心:使用 json 参数而不是 data 参数进行调用(例如)= {"i": 3, "j": 5, "dx": 7, "m": 8},您有可能混淆键。有时顺序很重要。 - MrNinjamannn

59

自从Flask 1.0发布以来,flask.testing.FlaskClient方法接受json参数,而且添加了Response.get_json方法,请参见pull request

    with app.test_client() as c:
        rv = c.post('/api/auth', json={
            'username': 'flask', 'password': 'secret'
        })
        json_data = rv.get_json()

为了与 Flask 0.x 兼容,您可以使用以下代码:

    from flask import Flask, Response as BaseResponse, json
    from flask.testing import FlaskClient
    
    
    class Response(BaseResponse):
        def get_json(self):
            return json.loads(self.data)
    
    
    class TestClient(FlaskClient):
        def open(self, *args, **kwargs):
            if 'json' in kwargs:
                kwargs['data'] = json.dumps(kwargs.pop('json'))
                kwargs['content_type'] = 'application/json'
            return super(TestClient, self).open(*args, **kwargs)
    

    app = Flask(__name__)
    app.response_class = Response
    app.test_client_class = TestClient
    app.testing = True

3
请勿忘记,json 参数必须是一个 dict 类型而不是 JSON 字符串! - Mathieu Dhondt
通过这个答案,无需创建自定义客户端覆盖post方法来使用JSON(在Flask 2.0.2中已检查)。 - cpinamtz

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