在Flask中测试文件上传

ham*_*nan 21 flask python-3.x python-unittest flask-testing

我正在使用Flask-Testing进行Flask集成测试.我有一个表格,上面有一个徽标文件,我正在尝试编写测试但是我一直收到错误说:TypeError: 'str' does not support the buffer interface.

我正在使用Python 3.我找到的最接近的答案是这个,但它对我不起作用.

这是我的许多尝试之一:

def test_edit_logo(self):
    """Test can upload logo."""
    data = {'name': 'this is a name', 'age': 12}
    data['file'] = (io.BytesIO(b"abcdef"), 'test.jpg')
    self.login()
    response = self.client.post(
        url_for('items.save'), data=data, follow_redirects=True)
    })
    self.assertIn(b'Your item has been saved.', response.data)
    advert = Advert.query.get(1)
    self.assertIsNotNone(item.logo)
Run Code Online (Sandbox Code Playgroud)

如何在Flask中测试文件上传?

ham*_*nan 22

问题最终不是当一个人添加content_type='multipart/form-data'post方法时,它希望所有值data都是文件或字符串.我的数据字典中有整数,我感谢这个评论.

所以最终的解决方案看起来像这样:

def test_edit_logo(self):
    """Test can upload logo."""
    data = {'name': 'this is a name', 'age': 12}
    data = {key: str(value) for key, value in data.items()}
    data['file'] = (io.BytesIO(b"abcdef"), 'test.jpg')
    self.login()
    response = self.client.post(
        url_for('adverts.save'), data=data, follow_redirects=True,
        content_type='multipart/form-data'
    )
    self.assertIn(b'Your item has been saved.', response.data)
    advert = Item.query.get(1)
    self.assertIsNotNone(item.logo)
Run Code Online (Sandbox Code Playgroud)

  • 我非常爱你,我现在就想吻你。我浪费了整整一个小时试图弄清楚出了什么问题......好先生,你是我的救世主。 (2认同)
  • 为了稍微揭开这一点,分配给“data['file']”的“类文件元组”中的值被转换为 [werkzeug.datastructs.FileMultiDict.add_file](https://werkzeug.palletsprojects .com/en/1.0.x/datastructs/#werkzeug.datastructs.FileMultiDict),因此它可以采用可选的第三个值来指定文件的“content_type”(与整个请求的 content_type 不同) (2认同)

mmc*_*han 16

你需要两件事:

1.) content_type='multipart/form-data'在你.post()
data=传球中file=(BytesIO(b'my file contents'), "file_name.jpg")

一个完整的例子:

    data = dict(
        file=(BytesIO(b'my file contents'), "work_order.123"),
    )

    response = app.post(url_for('items.save'), content_type='multipart/form-data', data=data)
Run Code Online (Sandbox Code Playgroud)

  • 如果文件系统中有文件,则需要对open(path_to_file,'rb')做为f:data ['file'] =(f,f.name)` (4认同)

Joe*_*icz 9

您可以使用 Werkzeug's FileStorage(由 Flask 在引擎盖下使用),您不需要安装它,因为它随 Flask 一起提供。

您可以模拟这样的文件:

from werkzeug.datastructures import FileStorage
import io
import json

# Here we are mocking a JSON file called Input.json
my_dict = {"msg": "hello!"}
input_json = json.dumps(my_dict, indent=4).encode("utf-8")

mock_file = FileStorage(
    stream=io.BytesIO(input_json),
    filename="Input.json",
    content_type="application/json",
)
Run Code Online (Sandbox Code Playgroud)

请注意,我在我的服务器上使用了一个真实的文件: tests/assets/my_video.mp4

from werkzeug.datastructures import FileStorage


my_video = os.path.join("tests/assets/my_video.mp4")

my_file = FileStorage(
    stream=open(my_video, "rb"),
    filename="my_video.mp4",
    content_type="video/mpeg",
),

rv = client.post(
   "/api/v1/video",
   data={
      "my_video": my_file,
   },
   content_type="multipart/form-data"
)
Run Code Online (Sandbox Code Playgroud)

测试以查看它返回 200 的响应状态代码:

assert "200" in rv.status
Run Code Online (Sandbox Code Playgroud)

然后我可以测试文件是否到达服务器上的测试目录:

assert "my_video.mp4" in os.listdir("tests/my_test_path")
Run Code Online (Sandbox Code Playgroud)

另请注意,您需要将模拟文件设置为None拆卸时,否则您将获得ValueError: I/O operation on closed file.. 下面是一个 Pytest 示例:

    def setup_method(self):
        self.mock_file = FileStorage(
            stream=io.BytesIO(input_json),
            filename="Input.json",
            content_type="application/json",
        )

    def teardown_method(self):
        self.mock_file = None
Run Code Online (Sandbox Code Playgroud)

  • 这对我有用,而接受的答案则不然。 (3认同)