Flask 端点在执行时返回状态 400 就好了

Flask Endpoint Returning Status 400 While Executing Just Fine

我目前正在为一个函数编写单元测试,该函数处理 JSON 过滤器字符串以使用 flask-csv 构建 CSV 文件。当我在应用程序中测试该功能时,它运行良好,使用正确的过滤器触发下载,并以预期格式返回文件。 检查 response.data 中的输出结果也很好,但是当 运行 测试时我一直得到 BadRequest (400)

这将是端点函数:

csv-download.py

import json
import logging

import flask_csv
import pandas as pd
from flask import Blueprint
from jinja2 import Template
from pydantic import ValidationError
from models import CSVModel

home_blueprint = Blueprint("home", __name__, url_prefix="/")

@home_blueprint.route("csv_download", methods=["GET", "POST"])
def download_csv():

    filter_str = request.args.get("filters")
    content = request.args.get("content")

    try:
        model = CSVModel(csv_fliters=filter_str, csv_content=content)
    except ValidationError as e:
        raise BadInputException(e.json())

    filters = json.loads(filter_str)


    with open(
        "bq_queries/myquery.bq", "r", encoding="utf-8"
    ) as file:
        query_string = file.read()

    query = Template(query_string)

    # this function is replaced by a mock.patch in the test
    data = load_from_query(apply_filters(query, filters, "None"), client)

    today = pd.Timestamp.today().strftime("%Y%m%d")
    start = pd.to_datetime(filters["order_date"][0]).strftime("%Y%m%d")
    end = pd.to_datetime(filters["order_date"][1]).strftime("%Y%m%d")

    response = flask_csv.send_csv(
        data.to_dict(orient="records"),
        f"{today}_{start}_until_{end}_{content}.csv".format(),
        list(data.columns),
    )

    return response

这个函数是这样测试的:

test_csv_download.py

import pytest  
from flask.testing import FlaskClient
from unittest.mock import patch

@patch('customer_feedback_hub.home.views.load_from_query')
def test_csv_download_(mock_load, client: FlaskClient) -> None:
    """
    Test verifying that the CSV-Download Endpoint works.

    """

    import pandas as pd
    import json

    mock_load.return_value = pd.DataFrame({'A': [1,2], 'B': [3,4]})

    test_filters = {'subentity_id': 1, 'order_date': ['2019-10-30', '2019-10-31']}

    suffix = "test"



    dl_filters = json.dumps(test_filters)

    response = client.get("/csv_download" +
    "?filters={}&content={}".format(dl_filters, suffix))

    # response format taken directly from:
    # https://github.com/Shir0kamii/Flask-CSV/blob/master/test_flask_csv.py

    expected = b"""A,B
    1,3
    2,4
    """.replace(b'\n', b"\r\n")

    response.data == expected

    assert response.status_code == 200

测试失败的消息:

====================================================================== FAILURES =======================================================================
_________________________________________________________________ test_csv_download_ __________________________________________________________________

mock_load = <MagicMock name='load_from_query' id='139751143251392'>, client = <FlaskClient <Flask 'customer_feedback_hub.app'>>

    @patch('customer_feedback_hub.home.views.load_from_query')
    def test_csv_download_(mock_load, client: FlaskClient) -> None:
        """
        Test verifying that the CSV-Download Endpoint works.

        """

        import pandas as pd
        import json

        mock_load.return_value = pd.DataFrame({'A': [1,2], 'B': [3,4]})

        test_filters = {'subentity_id': 1, 'order_date': ['2019-10-30', '2019-10-31']}

        suffix = "test"


        # start = pd.to_datetime(test_filters["order_date"][0]).strftime("%Y%m%d")
        # end = pd.to_datetime(test_filters["order_date"][1]).strftime("%Y%m%d")


        dl_filters = json.dumps(test_filters)

        response = client.get("/csv_download" +
        "?filters={}&content={}".format(dl_filters, suffix))

        # response format taken directly from:
        # https://github.com/Shir0kamii/Flask-CSV/blob/master/test_flask_csv.py

        expected = b"""A,B
        1,3
        2,4
        """.replace(b'\n', b"\r\n")

        response.data == expected

>       assert response.status_code == 200
E       assert 400 == 200
E         -400
E         +200

tests/home/test_views.py:79: AssertionError

此外,为了完整起见,在原始函数中使用了 CSVModel 的定义,我用它来验证字符串确实可以加载为 JSON 字符串

models.py

import json

from pydantic import BaseModel, Extra, NoneStr, validator


class CSVModel(BaseModel):
    """
    Example Pydantic model for validating json
    """

    csv_filters: str
    csv_content: NoneStr = None

    class Config:
        extra = Extra.forbid

    @validator("csv_filters")
    def filters_are_json(cls, v):
        try:
            dic = json.loads(v)
            dic.items()

        except Exception:
            raise ValueError("No JSON!")

也许我遗漏了一些明显的东西,但我很乐意看到另一双眼睛。

你有

response.data == expected

但你可能想要

assert response.data == expected

我怀疑断言会失败并告诉你更多。 :)