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

Flask单元测试未使用指定测试数据库,仍连接生产数据库的问题排查

Flask单元测试未使用指定测试数据库,仍连接生产数据库的问题排查

嘿,我看了你的问题,核心原因其实很明确:你修改数据库配置的时机太晚了!

你看,在你的测试文件里,你先执行了from app import app和from models import db, Pet,这时候app.py里的代码已经全部执行了——包括connect_db(app)和db.create_all(),这意味着数据库已经和生产库postgresql:///petagency建立了连接,之后你再修改app.config['SQLALCHEMY_DATABASE_URI']根本不会生效,因为连接已经在导入阶段就建立好了。

而CSRF配置生效是因为Flask-WTF的CSRF检查是在处理请求时动态读取配置的,不是在app初始化时就固定的,所以你之后修改的配置能被读取到。

下面给你两个可行的解决方案:

方案一:使用Flask应用工厂函数(推荐)

这是Flask项目的最佳实践,能彻底解决这类环境配置冲突的问题。你需要重构app.py,把应用初始化逻辑封装到一个函数里,这样测试时可以先传入测试配置,再创建应用:

修改app.py:

from flask import Flask, render_template, redirect, flash
from models import db, connect_db, Pet
from forms import AddPetForm, EditPetForm
from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, BooleanField, TextAreaField
from flask_debugtoolbar import DebugToolbarExtension
from sqlalchemy import exc
from werkzeug.utils import secure_filename
from flask_wtf.file import FileField, FileAllowed

def create_app(config_overrides=None):
    # 创建Flask实例
    app = Flask(__name__)
    
    # 设置默认配置
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///petagency'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['SQLALCHEMY_ECHO'] = True
    app.config['SECRET_KEY'] = "secret"
    app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
    
    # 如果有传入测试配置,覆盖默认配置
    if config_overrides:
        app.config.update(config_overrides)
    
    # 初始化调试工具栏
    DebugToolbarExtension(app)
    
    # 连接数据库
    connect_db(app)
    
    # 这里可以注册你的路由(如果之前路由是直接写在app.py里的,要移到这里)
    
    return app

# 只有当直接运行app.py时,才初始化应用并启动服务
if __name__ == "__main__":
    app = create_app()
    with app.app_context():
        db.create_all()
    app.run()

修改测试文件test_flask.py:

from unittest import TestCase
from app import create_app
from models import db, Pet

class PetAgencyTestCase(TestCase):
    def setUp(self):
        # 创建带测试配置的应用
        self.app = create_app({
            'SQLALCHEMY_DATABASE_URI': 'postgresql:///petagency_test',
            'SQLALCHEMY_ECHO': False,
            'TESTING': True,
            'WTF_CSRF_ENABLED': False
        })
        # 创建测试客户端
        self.client = self.app.test_client()
        
        # 在应用上下文里初始化测试数据库
        with self.app.app_context():
            db.drop_all()
            db.create_all()

    def tearDown(self):
        # 测试结束后清理数据库
        with self.app.app_context():
            db.session.remove()
            db.drop_all()
    
    # 在这里写你的测试用例,比如:
    def test_add_pet(self):
        with self.client as c:
            resp = c.post('/add', data={
                'name': 'TestPet',
                'species': 'Dog',
                'age': 3
            })
            self.assertEqual(resp.status_code, 302)
            
            with self.app.app_context():
                pet = Pet.query.filter_by(name='TestPet').first()
                self.assertIsNotNone(pet)

方案二:临时修复(不推荐,仅用于快速验证)

如果暂时不想重构代码,你可以在测试文件里修改配置后,重新初始化数据库连接:

from unittest import TestCase
from app import app
from models import db, Pet

# 先修改配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///petagency_test'
app.config['SQLALCHEMY_ECHO'] = False
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False

# 重新初始化数据库连接
db.init_app(app)

# 在应用上下文里重建测试库
with app.app_context():
    db.drop_all()
    db.create_all()

class PetAgencyTestCase(TestCase):
    # 测试用例...

这个方法的缺点是,app.py在导入时还是会先连接一次生产数据库,可能会产生不必要的副作用,所以还是推荐用应用工厂的方案。

备注:内容来源于stack exchange,提问作者Camden Tadhg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 06:54:35