设置follow_redirects=True后Flask应用pytest测试超时如何解决
问题根因
你遇到的卡死问题本质是测试用例之间的数据污染触发了无限重定向循环,具体逻辑如下:
- 你的
appfixture是session作用域,整个测试会话只会初始化一次数据库,不会每个测试用例自动重置数据。 test_email_reset_valid_auth运行完成后,会把测试用户的原邮箱myemail@gmail.com修改为newemail@gmail.com,后续test_email_reset_invalid_auth调用auth.login()默认还是用旧邮箱myemail@gmail.com登录,直接登录失败。- 如果你的
/confirm路由逻辑是「未登录用户自动重定向到登录页」,而登录页逻辑是「登录成功后自动跳转到之前访问的地址(也就是/confirm/xxx)」,就会形成/confirm -> /login -> /confirm的无限循环,follow_redirects=True会一直跟随重定向,最终表现为测试卡死。
这也完全符合你观察到的现象:注释掉前一个测试用例时,用户邮箱未被修改,登录正常,不会触发循环。
排查步骤
你可以通过以下操作确认问题:
- 打印重定向地址验证循环:在
test_email_reset_invalid_auth中关闭自动跟随重定向,打印跳转目标
response = client.get(f'/confirm/{token}', follow_redirects=False) print("重定向目标:", response.headers.get('Location'))
- 验证登录状态:在调用
auth.login()后查询当前登录用户信息,确认是否登录成功
auth.login() with app.app_context(): user = User.query.filter_by(email='myemail@gmail.com').first() print("原邮箱用户是否存在:", user is not None)
解决方案
有三种常用方案可选,按优先级排序:
方案1:新增数据库隔离fixture(推荐)
给每个测试用例加事务回滚逻辑,运行完自动重置数据,完全避免用例间污染,在conftest.py中新增如下fixture即可:
@pytest.fixture(scope="function") def db(app): with app.app_context(): # 开启事务 conn = _db.engine.connect() trans = conn.begin() yield _db # 测试结束回滚事务,恢复数据 trans.rollback() conn.close() _db.session.remove()
后续所有测试用例都声明依赖db fixture即可。
方案2:修改app fixture作用域
直接把app fixture的scope从session改为function,每个测试用例都重新初始化数据库,实现简单,缺点是测试运行速度会变慢。
@pytest.fixture(scope='function') def app(): # 原有逻辑不变
方案3:用例执行后手动恢复数据
在test_email_reset_valid_auth的断言后添加代码,把修改过的用户邮箱改回原值:
# 放在test_email_reset_valid_auth的assert之后 with app.app_context(): user.email = 'myemail@gmail.com' _db.session.commit()
额外优化
可以给测试请求加上最大重定向次数限制,避免后续再出现类似卡死问题:
response = client.get(f'/confirm/{token}', follow_redirects = True, max_redirects=5)
超过配置的重定向次数会直接抛出错误,不会无限等待。
内容的提问来源于stack exchange,提问作者Jonathan Bechtel
相关产品推荐
相关产品推荐

