烧瓶测试,文件归档和嵌套字典

Vas*_*dis 5 python multipartform-data flask

我创建了一个Flask应用,并想要对其进行测试。在单个端点中,我想发布一个多部分请求,其中包括一个文件和一个复杂的JSON对象。我首先考虑将werkzeug EnvironBuilder用于此任务,因为它似乎提供了一种非常自动化的方法,可以处理内容类型等。准备请求的代码段如下:

# client is an instance of FlaskClient produced using a pytest fixture and the method test client

def _post(endpoint, file_path=None, serialized_message=None):
        with open(file_path, 'rb') as fin:
                fil = io.BytesIO(fin.read())
        file_name = file_path.split(os.sep)[-1]
        builder = EnvironBuilder(path='/' + endpoint,
                                 method='POST',
                                  data=json.loads(
                                      serialized_message),
                                content_type="application/json")
        builder.files[file_name] = fil
        result = client.open(builder, buffered=True)
        return result
Run Code Online (Sandbox Code Playgroud)

失败并显示以下错误:

 def _add_file_from_data(self, key, value):
        """Called in the EnvironBuilder to add files from the data dict."""
        if isinstance(value, tuple):
            self.files.add_file(key, *value)
        elif isinstance(value, dict):
            from warnings import warn
            warn(DeprecationWarning('it\'s no longer possible to pass dicts '
                                    'as `data`.  Use tuples or FileStorage '
                                    'objects instead'), stacklevel=2)
            value = dict(value)
            mimetype = value.pop('mimetype', None)
            if mimetype is not None:
                value['content_type'] = mimetype
>           self.files.add_file(key, **value)
E           TypeError: add_file() got an unexpected keyword argument 'globalServiceOptionId'
Run Code Online (Sandbox Code Playgroud)

随着globalServiceOptionId是在我张贴的字典中的嵌套字典的关键。我有一些绕过这个问题的想法,可以将内部字典转换为jsons字符串,但是我希望得到更具体的答案,因为我不希望在测试内部和外部更改请求的表示形式。谢谢。

更新1

密码字典的形式并不重要,只要它内部嵌套了字典即可。在此示例中给出了此json:

{
    "attachments": [],
    "Ids": [],
    "globalServiceOptions": [{
      "globalServiceOptionId": {
        "id": 2,
        "agentServiceId": {
          "id": 2
        },
        "serviceOptionName": "Time",
        "value": "T_last",
        "required": false,
        "defaultValue": "T_last",
        "description": "UTC Timestamp",
        "serviceOptionType": "TIME"
      },
      "name": "Time",
      "value": null
    }]
  }
Run Code Online (Sandbox Code Playgroud)

更新2

我测试了另一个代码段:

    def _post(endpoint, file_path=None, serialized_message=None):
        with open(file_path, 'rb') as fin:
                fil = io.BytesIO(fin.read())
        files = {
         'file': (file_path, fil, 'application/octet-stream')
        }
        for key, item in json.loads(serialized_message).items():
            files[key] = (None, json.dumps(item), 'application/json')

        builder = EnvironBuilder(path='/' + endpoint,
                                 method='POST', data=files,
                                 )
        result = client.open(builder, buffered=True)
        return result
Run Code Online (Sandbox Code Playgroud)

尽管运行时没有错误,但Flask将(按预期)将传入的json识别为文件,这再次需要在测试和正常运行期间进行不同的处理。

bsp*_*ion 2

我遇到了类似的问题,最终对我有用的是更改数据方法以排除嵌套字典。获取示例 JSON,执行以下操作应该可以清除EnvironBuilder

data_json = {
    "attachments": [],
    "Ids": [],
    "globalServiceOptions": [json.dumps({  # Dump all nested JSON to a string representation
            "globalServiceOptionId": {
                "id": 2,
                "agentServiceId": {
                    "id": 2
                },
                "serviceOptionName": "Time",
                "value": "T_last",
                "required": false,
                "defaultValue": "T_last",
                "description": "UTC Timestamp",
                "serviceOptionType": "TIME"
            },
            "name": "Time",
            "value": null
        })
    ]
}
builder = EnvironBuilder(path='/' + endpoint,
                             method='POST',
                              data=data_json,
                            content_type="application/json")
Run Code Online (Sandbox Code Playgroud)

采用上述方法仍然允许正确传递嵌套的 dict/JSON,同时清除 werkzeug 限制。