如何修复Flask单元测试中的AssertionError: 400 != 302问题
问题描述
我在用Flask/Python编写单元测试,测试用户编辑接口的POST请求处理逻辑,但测试第一部分始终无法获取预期的302重定向状态码,报错AssertionError: 400 != 302。
测试代码
def test_edited_user(self): with app.test_client() as client: # 测试POST编辑数据后是否重定向 data = {'first_name': self.user_fn, 'last_name': self.user_ln} res = client.post(f'/users/{self.user_id}/edit', data=data) self.assertEqual(res.status_code, 302) # 测试重定向到/users页面 res = client.get('/users') html = res.get_data(as_text=True) self.assertEqual(res.status_code, 200) self.assertIn('has been updated', html)
对应路由/业务代码
@app.route('/users/<int:user_id>/edit', methods=['POST']) def edited_user(user_id): """接收表单数据编辑用户并更新数据库""" first_name = request.form['first_name'] last_name = request.form['last_name'] user = User.query.session.get(User, user_id) user.first_name = first_name user.last_name = last_name db.session.commit() flash(f'User has been updated to {first_name} {last_name}!') return redirect('/users')
我尝试过硬编码data = {'first_name': 'TestFirst', 'last_name': 'TestLast'},也试过设置content_type = 'application/json'但收到JSON未定义的错误。我认为这不是JSON问题,因为表单数据是通过HTML表单的文本输入提交的(如有错误请指正)。
排查与解决方案
400状态码表示请求不符合服务器要求,结合你的代码,主要排查以下几点:
测试用户数据未正确初始化
测试中用到的self.user_id对应的用户可能不存在。如果测试类的setUp方法没有提前创建并保存测试用户到数据库,User.query.session.get(User, user_id)会返回None,后续给user.first_name赋值时会抛出异常,最终导致Flask返回400错误。
解决:在setUp方法中创建测试用户,执行db.session.add(user)和db.session.commit(),确保self.user_id对应数据库中存在的记录。表单字段值为空或未正确传递
虽然你的路由代码没有做参数校验,但如果self.user_fn或self.user_ln是空值,可能触发底层的请求解析异常;另外要确认测试中传递的data确实包含first_name和last_name两个字段。
解决:打印data的实际内容,确保两个字段都有非空值;也可以在路由中添加参数校验逻辑,比如:from flask import abort def edited_user(user_id): first_name = request.form.get('first_name') last_name = request.form.get('last_name') if not first_name or not last_name: abort(400, description="Missing required fields") # 后续逻辑...Flask应用未配置SECRET_KEY
使用flash消息需要Flask应用设置SECRET_KEY,如果未配置,可能会抛出异常影响响应状态码。
解决:在测试配置中添加:app.config['SECRET_KEY'] = 'test-secret-key'数据库会话未正确管理
如果测试中使用了事务,要确保创建用户的会话已提交,否则数据库中没有对应的用户记录。
解决:在setUp中创建用户后务必提交会话,或者使用测试框架的事务回滚机制(比如pytest-flask的clientfixture自动处理)。
另外,你提到设置content_type='application/json'出现错误是正常的——你的路由用request.form解析表单数据,而不是request.get_json(),所以不需要设置这个Content-Type,测试客户端默认的application/x-www-form-urlencoded格式是正确的。
内容的提问来源于stack exchange,提问作者Ollypop

