簡體   English   中英

如何測試在 flask/flask-restx 中獲取解析器輸入的 GET 方法?

[英]How to test the GET method that takes parser inputs in flask/flask-restx?

我正在使用Flask-restx制作 flask 應用程序,我通過請求解析從用戶那里獲取輸入,如下所示:

from flask_restx import Resource, reqparse
from .services.calculator import DimensionCalculator
parser = reqparse.RequestParser()
parser.add_argument("dimensions", type=float,
                    required=True,
                    action='split',
                    help="Dimensions of the rectangle (in meters)")
parser.add_argument("angle_inclination", type=float,
                    required=True,
                    action='append',
                    help="Angle of inclination of the Dachfläche (Neigung)")
@ns.route("/output")
class UserOutput(Resource):
    @ns.expect(parser, validation=True)
    def get(self):
        args = parser.parse_args()
        return DimensionCalculator.inputs(**args)

其中ns是我定義的命名空間, DimensionCalculator.inputs的簡化版本是:

class DimensionCalculator:
    def inputs(**user_input):
        installation_place = user_input['installation_place']
        num_rectangles = user_input['num_rectangles']
        dimensions = user_input['dimensions']
        angle_inclination = user_input['angle_inclination']
        alignment = user_input['alignment']
        direction = user_input['direction']
        vendor = user_input['vendor']
        output = {
                    "installation_place": installation_place,
                    "num_rectangles": num_rectangles,
                    "area_shape": area_shape,
                    "vendor": vendor
                }
        return output

我正在使用pytest編寫測試。 我已經為所有類和方法編寫了測試,唯一無法測試的是UserOutput中定義的GET方法。 有沒有辦法測試GET方法?

任何幫助表示贊賞。

考慮到單元測試標簽,我將介紹我想出的關於如何完全隔離測試它的方法。 基本上, get方法對依賴項進行了兩次 function 調用,因此在單元意義上,您必須檢查是否確實進行了這些調用,以及斷言 arguments,對嗎?

用於示例的項目結構:

+---Project
|   |   
|   |   __init__.py
|   |   config.py
|   |   dimension_calculator.py
|   |   parser_impl.py
|   |   user_output.py
|   |   user_output_test.py

因此,為簡單起見,一切都是平坦的。

最重要的是,您必須將UserOutput模塊與依賴項分離。 您不應該像這樣對依賴項進行硬編碼:

from .services.calculator import DimensionCalculator

假設, DimensionCalculator可能包含復雜的業務邏輯,不應該出現在測試的 scope 中。 所以,下面是UserOutput模塊的樣子:

from flask_restx import Resource, Api
from flask import Flask
from .config import Config

app = Flask(__name__)
api = Api(app)
ns = api.namespace('todos', description='TODO operations')

@ns.route("/output")
class UserOutput(Resource):
    @ns.expect(Config.get_parser_impl(), validation=True)
    def get(self):
        args = Config.get_parser_impl().parse_args()
        return Config.get_dimension_calculator_impl().inputs(**args)


if __name__ == '__main__':
    app.run(debug=True)

如您所見,“外部”依賴現在可以很容易地被存根(這是一種稱為依賴注入的常見模式的一部分)。 配置模塊如下所示:

from .parser_impl import parser
from .dimension_calculator import DimensionCalculator


class Config(object):
    parser_impl = parser
    calculator = DimensionCalculator

    @staticmethod
    def configure_dimension_calculator_impl(impl):
        Config.calculator = impl

    @staticmethod
    def configure_parser_impl(impl):
        Config.parser_impl = impl

    @staticmethod
    def get_dimension_calculator_impl():
        return Config.calculator

    @staticmethod
    def get_parser_impl():
        return Config.parser_impl

最后但並非最不重要的一點是,我們將在其中存根依賴項並注入它們:

from .user_output import UserOutput
from flask import Flask
from .config import Config

class ParserStub(object):
    parse_args_call_count = 0
    @staticmethod
    def parse_args():
        ParserStub.parse_args_call_count = ParserStub.parse_args_call_count + 1
        return {'parser_stub': 2}

class DimensionCalculatorStub(object):
    inputs_call_count = 0
    @staticmethod
    def inputs(**args):
        DimensionCalculatorStub.inputs_call_count = DimensionCalculatorStub.inputs_call_count + 1
        return {'stub': 1}

app = Flask(__name__)

def test_user_request_get():
    with app.test_request_context():
        # given
        Config.configure_dimension_calculator_impl(DimensionCalculatorStub)
        Config.configure_parser_impl(ParserStub)
        uo = UserOutput()
        
        # when
        uo.get()
        
        # then
        assert DimensionCalculatorStub.inputs_call_count == 1
        assert ParserStub.parse_args_call_count == 1
        # assert arguments as well!

在我的情況下測試通過。 缺少的一件事是對 arguments 的驗證。

為了完整起見,我還將包括 DimensionCalculator 和解析器本身,盡管它們與您的示例完全相同。 我只是將它們模塊化:

from flask_restx import reqparse

parser = reqparse.RequestParser()
parser.add_argument("dimensions", type=float,
                    required=True,
                    action='split',
                    help="Dimensions of the rectangle (in meters)")
parser.add_argument("angle_inclination", type=float,
                    required=True,
                    action='append',
                    help="Angle of inclination of the Dachfläche (Neigung)")

和維度計算器.py:

class DimensionCalculator:
    @staticmethod
    def inputs(**user_input):
        installation_place = user_input['installation_place']
        num_rectangles = user_input['num_rectangles']
        dimensions = user_input['dimensions']
        angle_inclination = user_input['angle_inclination']
        alignment = user_input['alignment']
        direction = user_input['direction']
        vendor = user_input['vendor']
        output = {
                    "installation_place": installation_place,
                    "num_rectangles": num_rectangles,
                    "area_shape": "EMPTY",
                    "vendor": vendor
                }
        return output

重要的是肯定有專門的框架用於此類存根/模擬准備和配置(例如: https://pypi.org/project/pytest-mock/ )。 我只是想介紹這個概念和最簡單的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM