34

我在 Flask 上有一个使用 SqlAlchemy 来审核新闻的 Web 应用程序,它有一些 api 方法来处理审核请求,例如批准、拒绝当前选定的新闻、列出它们等。

我想为这些方法编写单元测试,并使它们工作,但我不明白如何在一个数据库会话中执行我从测试用例中执行的所有请求,以便我可以删除对数据库的所有更改。还是有另一种更清洁或正确的方法来做到这一点?

我发现也许我需要的只是 SqlAlchemy 中的“scoped_session”,但我实现它的所有尝试都失败了。如果这是正确的方法,请告诉我在哪里使用这行代码(在设置中,或在测试用例 set_up 方法中)。

from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
session_factory = sessionmaker()
Session = scoped_session(session_factory) 
4

3 回答 3

29

我建议你使用Flask-Testing扩展。这是一个经过批准的扩展,可让您根据需要进行单元测试。它也有一个针对 SQLAlchemy 的特定部分。

使用 SQLAlchemy 进行测试

如果您将 Flask-Testing 与 SQLAlchemy 一起使用,这涵盖了几点。假设您使用的是 Flask-SQLAlchemy 扩展,但如果不是,示例应该不会太难适应您自己的特定设置。

首先,确保将数据库 URI 设置为生产数据库以外的内容!其次,在每次测试运行时创建和删除表通常是个好主意,以确保干净的测试:"

from flask.ext.testing import TestCase

from myapp import create_app, db

class MyTest(TestCase):

    SQLALCHEMY_DATABASE_URI = "sqlite://"
    TESTING = True

    def create_app(self):

        # pass in test configuration
        return create_app(self)

    def setUp(self):

        db.create_all()

    def tearDown(self):

        db.session.remove()
        db.drop_all()
于 2013-07-22T16:14:32.213 回答
17

这就是我最近运行单元测试的方式。我假设因为您使用的是 SQLAlchemy,所以您正在使用模型类。我还假设您的所有表都定义为 SQLAlchemy 模型类。

from flask import Flask
import unittest

from app import db
from app.models import Log
from constants import test_logs

class appDBTests(unittest.TestCase):

    def setUp(self):
        """
        Creates a new database for the unit test to use
        """
        self.app = Flask(__name__)
        db.init_app(self.app)
        with self.app.app_context():
            db.create_all()
            self.populate_db() # Your function that adds test data.

    def tearDown(self):
        """
        Ensures that the database is emptied for next unit test
        """
        self.app = Flask(__name__)
        db.init_app(self.app)
        with self.app.app_context():
            db.drop_all()

由于您使用与应用程序相同的数据库设置,因此您可以在运行的每个单元测试中构建和销毁测试数据库。

于 2013-07-23T18:58:41.000 回答
14

关于 codegeek 使用 Flask-Testing 的答案,我很难理解createapp()它的作用。Flask-SqlAlchemy Introduction to Contexts为我提供了一些关于如何将 SQLAlchemy 对象动态绑定到应用程序的指针。在这种情况下,绑定到测试应用程序。

基本上:

  1. 创建烧瓶 sqlalchemy 对象但不传入 app 对象
  2. 在 create_app 函数中,创建您的测试应用程序,并动态绑定 SQLAlchemy。

你的myapp.py

# don't pass in the app object yet
db = SQLAlchemy()

def create_test_app():
    app = Flask(__name__)
    app.config['TESTING'] = True
    app.config["SQLALCHEMY_DATABASE_URI"] = "xxxxxxtestdatabasexxx"
    # Dynamically bind SQLAlchemy to application
    db.init_app(app)
    app.app_context().push() # this does the binding
    return app

# you can create another app context here, say for production
def create_production_app():
    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE_URI"] = "xxxxxxproductionxxxx"
    # Dynamically bind SQLAlchemy to application
    db.init_app(app)
    app.app_context().push()
    return app

然后,您可以按照 Flask-Test 文档中概述的 codegeek 的解决方案进行操作

from flask.ext.testing import TestCase
from myapp import create_app, db

class MyTest(TestCase):

    # I removed some config passing here
    def create_app(self):
        return create_test_app()

    def setUp(self):

        db.create_all()

    def tearDown(self):

        db.session.remove()
        db.drop_all()

这个解决方案的好处是您可以创建不同的应用程序并使用函数动态绑定 SQLAlchemy 对象。每个应用程序可以服务于不同的目的。例如,一个用于生产,一个用于单元测试。在生产的情况下,您可以在顶级烧瓶应用程序中调用 create_production_application()。

于 2016-08-08T08:44:23.950 回答