flask_sqlalchemy create_all()在单元测试中无声地失败

时间:2017-06-12 14:15:19

标签: python unit-testing flask flask-sqlalchemy

我正在为使用flask_sqlalchemy扩展名在Flask中编写的REST API编写单元测试。因为我有许多模型类,所以我编写了一个TestCase子类来执行测试数据库的标准setUp / cleanUp。我的所有测试类都继承自此。单独运行时每个测试都会成功,但是当我在一个类中运行多个测试时,第二个setUp()在self.db.session.commit()上失败(我试图在User表中添加一个条目),因为self.db.create_all()(无声地)无法创建任何表。 这是我的基础测试类,位于测试包的__init__.py中:

import unittest

from .test_client import TestClient
from .. import create_app
from pdb import set_trace as DBG

class ApiTest(unittest.TestCase):
    default_username = 'fred'
    default_password = 'bloggs'
    db = None

    def setUp(self):
        try:
            self.app = create_app('testing')
            self.addCleanup(self.cleanUp)
            self.ctx = self.app.app_context()
            self.ctx.push()
            from .. import db
            self.db = db
            self.db.session.commit()
            self.db.drop_all(app=self.app)
            from ..models import User, Player, Team, Match, Game
            # self.app.logger.debug('drop_all())')
            self.db.create_all(app=self.app)
            # self.app.logger.debug('create_all())')
            user = User(user_name=self.default_username)
            user.password = self.default_password
            self.db.session.add(u)
            self.db.session.commit()
            self.client = TestClient(self.app, user.generate_auth_token(), '')
        except Exception, ex:
            self.app.logger.error("Error during setUp: %s" % ex)
            raise

    def cleanUp(self):
        try:
            self.db.session.commit()
            self.db.session.remove()
            self.db.drop_all(app=self.app)
            # self.app.logger.debug('drop_all())')
            self.ctx.pop()
        except Exception, ex:
            self.app.logger.error("Error during cleanUp: %s" % ex)
            raise

有人能告诉我这里有什么问题吗?

编辑:根据要求添加了create_app()的代码。

# chessleague/__init__.py
import os

from flask import Flask, g
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager


from . import config


app = None
db = None  # The database, initialised in create_app()


def create_app(config_name):
    app = Flask(__name__)
    app.config.update(config.get_config(config_name))
    # if app.config['USE_TOKEN_AUTH']:
    #     from api.token import token as token_blueprint
    #     app.register_blueprint(token_blueprint, url_prefix='/auth')
    import logging
    from logging.handlers import SysLogHandler
    syslog_handler = SysLogHandler()
    syslog_handler.setLevel(logging.WARNING)
    app.logger.addHandler(syslog_handler)

    login_manager = LoginManager()
    login_manager.login_view = 'auth.login'
    login_manager.init_app(app)
    global db
    db = SQLAlchemy(app)
    db.init_app(app)
    from .models import User,Player,Game,Match,Team,Post
    db.create_all()
    from .api import api as api_blueprint
    app.register_blueprint(api_blueprint, url_prefix='/chessleague')
    return app

`

2 个答案:

答案 0 :(得分:1)

create_all()适用于通过导入带模型的模块发现的元数据。在你的情况下,模特'元数据绑定到db的{​​{1}},但您从models.py create_all()调用chessleague/__init__.db,这是SqlAlchemy的不同对象。您可以使用create_app()中的db来解决此问题:

models.py

答案 1 :(得分:0)

这是适用于我的初始化序列 - 欢迎评论!

我的测试班setUp()从主应用包调用create_app(config_name)。 主应用程序包(__init__.py)在模块级别创建应用程序实例,即app=Flask(my_app_package_name) 然后我的功能 create_app(config_name)

  • 将正确的配置加载到app.config(包括正确的SQLACHEMY_DATABASE_URL)
  • 从models.py
  • 导入模型类和db(作为model_db

此导入在models.py中的模块级别创建符号db,后跟模型类定义:

  # models.py
    from . import app
    db = SQLAlchemy(app)
    ...
    class User(db.Model)
    ... 
    etc

现在一切都设置正确:可以从models.py中的任何位置导入符号'db',我可以从我的测试db.create_all()成功调用setUp()

@Fian,你可以发布你的解决方案作为答案,所以我可以给你信用吗?