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)