You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

最新版pytest中如何实现测试前后数据库创建清理并保留断言报错?

解决方案

核心问题分析

你之前的错误有两个关键点:

  1. 测试函数里用yield无效:pytest的yield是用来实现fixture的setup/teardown逻辑的,只能在fixture函数中生效,测试函数内部的yield只是普通生成器,不会触发清理操作。
  2. 模型和测试逻辑存在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

为什么这个方案有效?

  1. Fixture的yield机制:pytest会自动识别fixture中的yield,执行完测试函数后运行yield后的清理代码,无论测试成功还是失败,都能保证数据库被清理。
  2. 统一的SECRET_KEY:模型用配置中的密钥生成和验证token,解决了之前token永远无效的问题。
  3. 测试逻辑清晰:测试函数只关注业务逻辑验证,资源管理交给fixture,符合pytest的最佳实践。

内容的提问来源于stack exchange,提问作者kihnihih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 11:26:11