[英]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.