SQLAlchemy DetachedInstance在使用 Flask 进行单元测试时出错app.test_clien



我的目标是能够使用 Flask 应用程序测试路线test_client使用 self.client.post(url, ... .我遇到的问题是,每当我使用它发出请求时,我都会从 SQLAlchemy 遇到 DetachedInstanceError,说刷新或延迟加载操作无法发生。

这是我的设置:

class BaseTestCase(unittest.TestCase):
   def setUp(self):
      self.postgresql = Postgresql()
      config = {
         'FLASK_ENV': 'test',
         'SQLALCHEMY_DATABASE_URI': self.postgresql.url()
      }
      with patch.dict('os.environ', config):
         self.app = create_app()
         self.client = self.app.test_client()
         ctx = self.app.app_context()
         ctx.push()
         db.create_all()
         self.assertEqual(app.testing, True)
      reset_fake_data()
   def tearDown(self):
      db.session.remove()
      self.postgresql.stop()
   def post(self, url, data={}, headers={}):
      headers = {'Content-Type': 'application/json', **headers}
      return self.client.post(url, headers=headers, data=json.dumps(data))
   def post_with_auth_token(self, url, data={}, headers={}):
      headers = {'Authorization': f'Bearer {self.auth_token}'}
      return self.post(url, headers=headers, data=data)

然后在另一个文件中,我用response = self.post('/api/users/register', data=data)调用它并收到错误:

sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <User at 0x10ea43f98> is not bound to a Session; lazy load operation of attribute 'courses' cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)

以下是路线。我创建一个用户对象,然后尝试向其添加课程,但显然,当我尝试执行user.courses.append时,它无法延迟加载课程。我已经考虑过禁用 expire_on_commit 属性,但我不确定仅在测试的情况下如何做到这一点,或者是否有更好的方法来解决这个问题。

我读到从懒惰加载转换为急切加载也可以修复它,但我宁愿让事情懒惰加载,当我将关系设置为lazy='subquery'时,它似乎并没有修复它。

@users.route('/register', methods=['POST'])
def register():
   data = request.get_json()
   try:
      user = User.from_data(**data)
   except UnprocessableEntity:
      return jsonify(msg='Missing parameters'), 422
   except Conflict:
      return jsonify(msg='Email already exists'), 409
   except Unauthorized:
      return jsonify(msg='Unauthorized'), 401
   if data.get('invitation_token'):
      invite = CourseInvite.query.filter_by(token=data['invitation_token']).first_or_404('Invite not found')
      if invite.email and invite.email != user.email:
         return jsonify(msg='Email mismatch'), 401
      elif invite.used:
         return jsonify(msg='Invite already used'), 401
      user.courses.append(CourseEnrollment(course_id=invite.course.id))
      invite.used = True
   db.session.add(user)
   db.session.commit()
   return jsonify(msg='User successfully created'), 201

尝试这样的事情

class BaseTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        self.postgresql = Postgresql()
        config = {
            'FLASK_ENV': 'test',
            'SQLALCHEMY_DATABASE_URI': self.postgresql.url()
        }
        with patch.dict('os.environ', config):
            self.app = create_app()
            self.client = self.app.test_client()
            self.app.app_context().push()
    def setUp(self):
        with self.app.app_context():
            db.create_all()
            self.assertEqual(app.testing, True)
        reset_fake_data()
    def tearDown(self):
        with self.app.app_context():
            db.session.remove()
            self.postgresql.stop()
    def post(self, url, data={}, headers={}):
        headers = {'Content-Type': 'application/json', **headers}
        return self.client.post(url, headers=headers, data=json.dumps(data))
    def post_with_auth_token(self, url, data={}, headers={}):
        headers = {'Authorization': f'Bearer {self.auth_token}'}
        return self.post(url, headers=headers, data=data)

相关内容

最新更新