最新版pytest中如何实现测试前后数据库创建清理并保留断言报错?
解决方案
核心问题分析
你之前的错误有两个关键点:
- 测试函数里用yield无效:pytest的
yield是用来实现fixture的setup/teardown逻辑的,只能在fixture函数中生效,测试函数内部的yield只是普通生成器,不会触发清理操作。 - 模型和测试逻辑存在bug:User模型中生成和验证token用了随机生成的SECRET_KEY,导致永远验证失败;测试函数里的URL、用户查询逻辑也存在错误。
步骤1:用Fixture管理数据库生命周期
在conftest.py中新增一个fixture,专门处理数据库的创建和清理,这是pytest推荐的资源管理方式:
@pytest.fixture() def token_app_context(): app = create_app(TokenPytestConfig) with app.app_context(): # Setup:创建所有数据库表 db.create_all() yield # 暂停,执行测试函数逻辑 # Teardown:测试完成后清理数据库 db.session.remove() db.drop_all()
这个fixture会在每个依赖它的测试函数执行前创建表,测试结束后自动清理,不需要在测试函数里手动写创建/删除逻辑。
步骤2:修复User模型的Token逻辑
模型里的create_token和verify_token用了随机生成的SECRET_KEY,导致生成的token永远无法验证通过,要改用Flask配置中的密钥:
# models.py 修改后的代码片段 from flask import current_app class User(UserMixin, db.Model): # ... 其他字段和初始化方法保持不变 ... def create_token(self, expires_sec=1800): # 使用配置中的SECRET_KEY,而非随机生成 s = Serializer(current_app.config['SECRET_KEY'], expires_sec) return s.dumps({'user_id': self.id}).decode('utf-8') @staticmethod def verify_token(token): s = Serializer(current_app.config['SECRET_KEY']) try: user_id = s.loads(token)['user_id'] except: return None # 修复原代码的缩进错误:return要和try-except对齐 return User.query.get(user_id)
步骤3:修正测试函数逻辑
去掉测试函数里无效的yield和手动数据库操作,依赖新增的fixture,同时修复URL、查询逻辑的错误:
# test_routes.py 修改后的代码 def test_verified_email(token_client, new_user, token_app_context): ''' GIVEN a Flask application configured for testing WHEN the "/verified_email/<token>" request is (GET) THEN check that the token verification works correctly. ''' # 将测试用户添加到数据库 db.session.add(new_user) db.session.commit() # 获取用户并生成有效token user = User.query.get(new_user.id) valid_token = user.create_token() # 发送正确的GET请求(替换占位符为实际token) response = token_client.get(f"/verified_email/{valid_token}", follow_redirects=True) assert response.status_code == 200 # 验证有效token能正确识别用户 verify_result = User.verify_token(valid_token) assert verify_result is not None assert verify_result.id == user.id # 测试无效token的情况 invalid_token = valid_token + "invalid_suffix" invalid_result = User.verify_token(invalid_token) assert invalid_result is None
为什么这个方案有效?
- Fixture的yield机制:pytest会自动识别fixture中的yield,执行完测试函数后运行yield后的清理代码,无论测试成功还是失败,都能保证数据库被清理。
- 统一的SECRET_KEY:模型用配置中的密钥生成和验证token,解决了之前token永远无效的问题。
- 测试逻辑清晰:测试函数只关注业务逻辑验证,资源管理交给fixture,符合pytest的最佳实践。
内容的提问来源于stack exchange,提问作者kihnihih
相关产品推荐
相关产品推荐

