Flask Class 视图和蓝图测试用例失败
Flask Class views and Blueprints test case failure
我正在处理 Flask class 视图和蓝图问题,其中需要创建路由以添加和列出学生进出数据库。无法通过测试。失败说
TypeError: <StudentModel 1> is not JSON serializable
不确定这是否是解决问题的正确方法。请指导
StudentView.py
from flask import request, json, Response, Blueprint,jsonify
from flask import render_template
from flask_cors import CORS, cross_origin
from ..models.StudentModel import StudentModel, StudentSchema
#Add your code here
stu =Blueprint('stu', __name__,url_prefix='/api/students')
# Create routes to add a student to the database.
@stu.route('/add',methods=['POST'])
def add():
r = request.json
id = r['id']
student_name=r['student_name']
student_age=r['student_age']
sm =StudentModel(r)
sm.update(r)
sm.save()
x=sm.get_student_id(id)
if request.method == 'POST':
return Response(json.dumps(r),status= 201)
# Create routes to list all the added students
@stu.route('/')
def getstudents():
users =StudentModel.query.all()
return jsonify(users)
StudentModel.py
class StudentModel(db.Model):
#Table name
__tablename__ = 'student'
id = db.Column(db.Integer, primary_key=True)
student_name = db.Column(db.String(128), nullable=False)
student_age = db.Column(db.Integer, nullable=False)
#class constructor
def __init__(self, data):
self.id = data.get('id')
self.student_name = data.get('student_name')
self.student_age= data.get('student_age')
def save(self):
db.session.add(self)
db.session.commit()
def update(self, data):
for key, item in data.items():
setattr(self, key, item)
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
@staticmethod
def get_all_students():
return StudentModel.query.all()
@staticmethod
def get_student_id(id):
return StudentModel.query.filter_by(id=id).first()
def __repr(self):
return '<id {}>'.format(self.id)
class StudentSchema(Schema):
id = fields.Int(required=True)
student_name= fields.Str(required=True)
student_age = fields.Int(required=True)
app.py
from src.views.StudentView import stu
app.register_blueprint(stu)
test.py
import pytest
from api import app, db
import json
import base64
from flask import Flask
import os
from src.models.StudentModel import StudentModel
from src.models.TeacherModel import TeacherModel
class Test_API:
client = app.test_client()
@pytest.fixture(autouse=True, scope='session')
def setUp(self):
app.config['TESTING'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///testing.db'
db.create_all()
yield db
os.remove('testing.db')
def test_student_in_db(self):
result = StudentModel.query.all()
assert len(result) == 0
assert result == []
def test_students_list(self):
url = "api/students/"
response = self.client.get(url)
assert response.status_code == 200
assert response.json == []
def test_students_register_method(self):
url = "/api/students/add"
payload = '{"id": 1,"student_age": 16 , "student_name": "testname"}'
headers = { 'Content-Type': "application/json", 'cache-control': "no-cache" }
response = self.client.post(url, data=payload, headers=headers)
assert response.status_code == 201
assert response.json['message'] == 'Added student to the list'
def test_data_in_db_after_adding(self):
result = StudentModel.query.all()
assert len(result) == 1
assert result[0].student_name == 'testname'
def test_after_adding_students(self):
url = "api/students/"
response = self.client.get(url)
assert response.status_code == 200
assert response.json == [{'id': 1, 'student_age': 16, 'student_name': 'testname'}]
测试失败:
Test_API.test_after_adding_students _________________________________
self = <tests.tests_routes.Test_API object at 0x7fb88ce5df98>
def test_after_adding_students(self):
url = "api/students/"
> response = self.client.get(url)
tests/tests_routes.py:49:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:1006: in get
return self.open(*args, **kw)
/home/user/.local/lib/python3.5/site-packages/flask/testing.py:227: in open
follow_redirects=follow_redirects,
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:970: in open
response = self.run_wsgi_app(environ.copy(), buffered=buffered)
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:861: in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:1096: in run_wsgi_app
app_rv = app(environ, start_response)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2463: in __call__
return self.wsgi_app(environ, start_response)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2449: in wsgi_app
response = self.handle_exception(e)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1866: in handle_exception
reraise(exc_type, exc_value, tb)
/home/user/.local/lib/python3.5/site-packages/flask/_compat.py:39: in reraise
raise value
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2446: in wsgi_app
response = self.full_dispatch_request()
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1951: in full_dispatch_request
rv = self.handle_user_exception(e)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1820: in handle_user_exception
reraise(exc_type, exc_value, tb)
/home/user/.local/lib/python3.5/site-packages/flask/_compat.py:39: in reraise
raise value
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1949: in full_dispatch_request
rv = self.dispatch_request()
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1935: in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
src/views/StudentView.py:39: in getstudents
return jsonify(users)
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:370: in jsonify
dumps(data, indent=indent, separators=separators) + "\n",
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:211: in dumps
rv = _json.dumps(obj, **kwargs)
/usr/lib/python3.5/json/__init__.py:237: in dumps
**kw).encode(obj)
/usr/lib/python3.5/json/encoder.py:198: in encode
chunks = self.iterencode(o, _one_shot=True)
/usr/lib/python3.5/json/encoder.py:256: in iterencode
return _iterencode(o, 0)
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:100: in default
return _json.JSONEncoder.default(self, o)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <flask.json.JSONEncoder object at 0x7fb88ce241d0>, o = <StudentModel 1>
def default(self, o):
"""Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
"""
> raise TypeError(repr(o) + " is not JSON serializable")
E TypeError: <StudentModel 1> is not JSON serializable
解决问题的方法是一个一个地检查错误。
第一个错误来自一项测试,该测试检查添加新学生的响应是否是 HTTP 代码 201(已创建),而不是您的代码 returns 200(确定)。您的代码 returns 200 的原因是因为如果您没有指定任何其他内容(并且在处理请求时没有错误),那是 Flask 的默认设置。要解决这个问题,请在网上搜索如何 return 在 Flask 中自定义 http 代码。
第二个错误来自一项测试,该测试期望在查询所有学生时出现这名先前添加的学生。从技术上讲,此测试取决于首先添加学生的第一个测试。此测试失败的原因是因为在您的 add
函数中没有与数据库交互。检查 StudentModel
上的方法并尝试使用请求数据在您的数据库中创建一个新条目。好的 google 这里的关键字是“SQLAlchemy insert”或“SQLAlchemy save new object to database”。
修复第二个错误后,第三个错误应该也会消失。它还会测试是否添加了用户,但通过使用 API 获取用户更进一步,它还会检查是否使用了正确的用户数据。
其余测试的工作方式非常相似,只是针对教师而非学生。
你可以这样做:
from flask import request, json, Response, Blueprint
from flask import render_template
from flask_cors import CORS, cross_origin
from ..models.StudentModel import StudentModel, StudentSchema
#Add your code here
stu= Blueprint('student', __name__, url_prefix="/api/students")
# Create routes to add a student to the database.
@stu.route('/add',methods=['POST'])
def add():
if request.method=='POST':
r = request.get_json()
sm =StudentModel(r)
sm.update(r)
sm.save()
resp = json.jsonify({'message': "Added student to the list"})
resp.status_code = 201
return resp
# Create routes to list all the added students
@stu.route('/',methods=['GET'])
def view():
studs = StudentModel.get_all_students()
res = [{'id':s.id, 'student_name':s.student_name, 'student_age':s.student_age} for s in studs]
return json.jsonify(res)
我正在处理 Flask class 视图和蓝图问题,其中需要创建路由以添加和列出学生进出数据库。无法通过测试。失败说
TypeError: <StudentModel 1> is not JSON serializable
不确定这是否是解决问题的正确方法。请指导
StudentView.py
from flask import request, json, Response, Blueprint,jsonify
from flask import render_template
from flask_cors import CORS, cross_origin
from ..models.StudentModel import StudentModel, StudentSchema
#Add your code here
stu =Blueprint('stu', __name__,url_prefix='/api/students')
# Create routes to add a student to the database.
@stu.route('/add',methods=['POST'])
def add():
r = request.json
id = r['id']
student_name=r['student_name']
student_age=r['student_age']
sm =StudentModel(r)
sm.update(r)
sm.save()
x=sm.get_student_id(id)
if request.method == 'POST':
return Response(json.dumps(r),status= 201)
# Create routes to list all the added students
@stu.route('/')
def getstudents():
users =StudentModel.query.all()
return jsonify(users)
StudentModel.py
class StudentModel(db.Model):
#Table name
__tablename__ = 'student'
id = db.Column(db.Integer, primary_key=True)
student_name = db.Column(db.String(128), nullable=False)
student_age = db.Column(db.Integer, nullable=False)
#class constructor
def __init__(self, data):
self.id = data.get('id')
self.student_name = data.get('student_name')
self.student_age= data.get('student_age')
def save(self):
db.session.add(self)
db.session.commit()
def update(self, data):
for key, item in data.items():
setattr(self, key, item)
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
@staticmethod
def get_all_students():
return StudentModel.query.all()
@staticmethod
def get_student_id(id):
return StudentModel.query.filter_by(id=id).first()
def __repr(self):
return '<id {}>'.format(self.id)
class StudentSchema(Schema):
id = fields.Int(required=True)
student_name= fields.Str(required=True)
student_age = fields.Int(required=True)
app.py
from src.views.StudentView import stu
app.register_blueprint(stu)
test.py
import pytest
from api import app, db
import json
import base64
from flask import Flask
import os
from src.models.StudentModel import StudentModel
from src.models.TeacherModel import TeacherModel
class Test_API:
client = app.test_client()
@pytest.fixture(autouse=True, scope='session')
def setUp(self):
app.config['TESTING'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///testing.db'
db.create_all()
yield db
os.remove('testing.db')
def test_student_in_db(self):
result = StudentModel.query.all()
assert len(result) == 0
assert result == []
def test_students_list(self):
url = "api/students/"
response = self.client.get(url)
assert response.status_code == 200
assert response.json == []
def test_students_register_method(self):
url = "/api/students/add"
payload = '{"id": 1,"student_age": 16 , "student_name": "testname"}'
headers = { 'Content-Type': "application/json", 'cache-control': "no-cache" }
response = self.client.post(url, data=payload, headers=headers)
assert response.status_code == 201
assert response.json['message'] == 'Added student to the list'
def test_data_in_db_after_adding(self):
result = StudentModel.query.all()
assert len(result) == 1
assert result[0].student_name == 'testname'
def test_after_adding_students(self):
url = "api/students/"
response = self.client.get(url)
assert response.status_code == 200
assert response.json == [{'id': 1, 'student_age': 16, 'student_name': 'testname'}]
测试失败:
Test_API.test_after_adding_students _________________________________
self = <tests.tests_routes.Test_API object at 0x7fb88ce5df98>
def test_after_adding_students(self):
url = "api/students/"
> response = self.client.get(url)
tests/tests_routes.py:49:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:1006: in get
return self.open(*args, **kw)
/home/user/.local/lib/python3.5/site-packages/flask/testing.py:227: in open
follow_redirects=follow_redirects,
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:970: in open
response = self.run_wsgi_app(environ.copy(), buffered=buffered)
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:861: in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
/home/user/.local/lib/python3.5/site-packages/werkzeug/test.py:1096: in run_wsgi_app
app_rv = app(environ, start_response)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2463: in __call__
return self.wsgi_app(environ, start_response)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2449: in wsgi_app
response = self.handle_exception(e)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1866: in handle_exception
reraise(exc_type, exc_value, tb)
/home/user/.local/lib/python3.5/site-packages/flask/_compat.py:39: in reraise
raise value
/home/user/.local/lib/python3.5/site-packages/flask/app.py:2446: in wsgi_app
response = self.full_dispatch_request()
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1951: in full_dispatch_request
rv = self.handle_user_exception(e)
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1820: in handle_user_exception
reraise(exc_type, exc_value, tb)
/home/user/.local/lib/python3.5/site-packages/flask/_compat.py:39: in reraise
raise value
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1949: in full_dispatch_request
rv = self.dispatch_request()
/home/user/.local/lib/python3.5/site-packages/flask/app.py:1935: in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
src/views/StudentView.py:39: in getstudents
return jsonify(users)
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:370: in jsonify
dumps(data, indent=indent, separators=separators) + "\n",
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:211: in dumps
rv = _json.dumps(obj, **kwargs)
/usr/lib/python3.5/json/__init__.py:237: in dumps
**kw).encode(obj)
/usr/lib/python3.5/json/encoder.py:198: in encode
chunks = self.iterencode(o, _one_shot=True)
/usr/lib/python3.5/json/encoder.py:256: in iterencode
return _iterencode(o, 0)
/home/user/.local/lib/python3.5/site-packages/flask/json/__init__.py:100: in default
return _json.JSONEncoder.default(self, o)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <flask.json.JSONEncoder object at 0x7fb88ce241d0>, o = <StudentModel 1>
def default(self, o):
"""Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
"""
> raise TypeError(repr(o) + " is not JSON serializable")
E TypeError: <StudentModel 1> is not JSON serializable
解决问题的方法是一个一个地检查错误。
第一个错误来自一项测试,该测试检查添加新学生的响应是否是 HTTP 代码 201(已创建),而不是您的代码 returns 200(确定)。您的代码 returns 200 的原因是因为如果您没有指定任何其他内容(并且在处理请求时没有错误),那是 Flask 的默认设置。要解决这个问题,请在网上搜索如何 return 在 Flask 中自定义 http 代码。
第二个错误来自一项测试,该测试期望在查询所有学生时出现这名先前添加的学生。从技术上讲,此测试取决于首先添加学生的第一个测试。此测试失败的原因是因为在您的 add
函数中没有与数据库交互。检查 StudentModel
上的方法并尝试使用请求数据在您的数据库中创建一个新条目。好的 google 这里的关键字是“SQLAlchemy insert”或“SQLAlchemy save new object to database”。
修复第二个错误后,第三个错误应该也会消失。它还会测试是否添加了用户,但通过使用 API 获取用户更进一步,它还会检查是否使用了正确的用户数据。
其余测试的工作方式非常相似,只是针对教师而非学生。
你可以这样做:
from flask import request, json, Response, Blueprint
from flask import render_template
from flask_cors import CORS, cross_origin
from ..models.StudentModel import StudentModel, StudentSchema
#Add your code here
stu= Blueprint('student', __name__, url_prefix="/api/students")
# Create routes to add a student to the database.
@stu.route('/add',methods=['POST'])
def add():
if request.method=='POST':
r = request.get_json()
sm =StudentModel(r)
sm.update(r)
sm.save()
resp = json.jsonify({'message': "Added student to the list"})
resp.status_code = 201
return resp
# Create routes to list all the added students
@stu.route('/',methods=['GET'])
def view():
studs = StudentModel.get_all_students()
res = [{'id':s.id, 'student_name':s.student_name, 'student_age':s.student_age} for s in studs]
return json.jsonify(res)