Flask 测试客户端返回请求的"method not allowed",即使 Web 客户端工作正常



我最近重构了我的烧瓶应用程序,将视图与初始化文件分开。

我的结构是这样的:

api
__init__.py
views.py

我的应用程序最初是这样的:

import os
from flask import Flask

def create_app(test_config=None):
# create and configure the app
app = Flask(__name__)
setup_db(app)
CORS(app)
# CORS Headers 
@app.after_request
def after_request(response):
"""Docstring for my function"""
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response

# my views were all contained below
@app.route('/hello')
def hello():
return 'Hello, World!'  
return app

然后我重构为在其他地方定义并在create_app中引用:

API/初始化.py

from .views import hello
def create_app():
...
app.route('/hello')(hello)
app.route('/hello', methods=['POST'])(create_hello)    

接口/视图.py

def hello():
return 'Hello, World!'
def create_hello():
return 'something else'

我有一个pytest文件,用于测试hello的创建:

@pytest.fixture()
def set_up():
app = create_app()
client = app.test_client
database_path = "postgresql://{}:{}@{}/{}".format(username, password,'localhost:5432', test_db_name)
setup_db(app, database_path)

with app.app_context():
db = SQLAlchemy()
db.init_app(app)
db.create_all()
return client        


def test_create_hello(set_up):
client = set_up()
res = client.post('/hello', json={"name":"jim-bob")
data = json.loads(res.data)        
assert res.status_code == 200
assert data['success'] == True

当我运行pytest时,我的每个方法都收到类似的错误:

def test_create_hello(set_up):
client = set_up()
res = client.post('/hello', json={'name':'jim-bob')
>       data = json.loads(res.data)
test_api.py:128: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/python3.6/json/__init__.py:354: in loads
return _default_decoder.decode(s)
/usr/lib/python3.6/json/decoder.py:339: in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <json.decoder.JSONDecoder object at 0x7f069b43dc18>
s = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">n<title>405 Method Not Allowed</title>n<h1>Method Not Allowed</h1>n<p>The method is not allowed for the requested URL.</p>n'
idx = 0
def raw_decode(self, s, idx=0):
"""Decode a JSON document from ``s`` (a ``str`` beginning with
a JSON document) and return a 2-tuple of the Python
representation and the index in ``s`` where the document ended.

This can be used to decode a JSON document from a string that may
have extraneous data at the end.

"""
try:
obj, end = self.scan_once(s, idx)
except StopIteration as err:
>           raise JSONDecodeError("Expecting value", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

我的 api 仍然可以在浏览器中或使用 curl 工作,但由于某种原因测试不再有效。

自从我在create_app函数之外重构视图以来,我才遇到这个问题。 谁能看到可能导致这种情况的原因?

@app.route('/hello')

这仅将GET方法绑定到处理程序。

然而在这里:

res = client.post('/hello', json={'name': 'jim-bob'})

你正在做一个POST

要使同一处理程序也处理POST请求,请执行以下操作:

@app.route('/hello', methods=['GET', 'POST'])

或者为POST请求添加不同的处理程序。请参阅文档。

正如@hoefing指出的那样,从"/hello"路由方法返回的响应只是一个字符串。该响应将包装在烧瓶基响应类中,默认情况下,该类的内容类型为文本/HTML。因此,您的响应被测试函数捕获并加载为 JSON 时面临解码错误。

您添加的测试应根据返回的响应内容类型处理响应,在本例中不是 JSON。

#solutions 解决问题

  1. (解决方案 1( 更新"/hello"路由的响应。为此,您可以使用内容类型标头自行初始化烧瓶响应类,也可以使用烧瓶 jsonify自动执行此操作。

    from flask import make_response, jsonify
    def hello():
    #headers = {'Content-Type': 'application/json'}
    #return make_response('Hello, World!', 200, headers)
    return jsonify('Hello, World!')
    
  2. (解决方案 2( 更新测试逻辑以处理文本/HTML 响应。

    def test_create_hello(set_up):
    client = set_up()
    res = client.post('/hello', json={'name':'jim-bob')
    data = res.data
    # handle this html text data
    

你需要像这样重写你的代码

@app.route('/hello', methods=['GET', 'POST'])
def hello():
if flask.request.method == 'POST':
...
else:  # GET
...

相关内容

最新更新