web-dev-qa-db-ja.com

SQLAlchemyを使用するFlaskアプリケーションをどのようにテストできますか?

Flaskでニュースのモデレート用のSqlAlchemyを使用して動作しているWebアプリケーションがあります。承認、現在選択されているニュースの拒否、それらの一覧表示など、モデレート要求を処理するためのAPIメソッドがいくつかあります。

このメソッドに単体テストを記述したいと思い、それらを機能させましたが、データベースへのすべての変更を削除できるように、1つのdbセッションでテストケースから実行するすべての要求の実行を実装する方法がわかりません。またはこれを行う別のクリーナーまたは適切な方法はありますか?

SqlAlchemyで「scoped_session」が必要なだけかもしれませんが、それを実装しようとする試みはすべて失敗しました。それが正しい方法である場合は、このコード行をどこで使用するか(設定またはテストケースのset_upメソッドで)教えてください。

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

Flask-Testing 拡張を使用することをお勧めします。これは承認された拡張機能で、必要に応じて単体テストを実行できます。 SQLAlchemy専用のセクションもあります。

SQLAlchemyを使用したテスト

SQLAlchemyでFlask-Testingを使用している場合、これはいくつかの点をカバーしています。 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()
21
codegeek

これは私が最近ユニットテストを実行している方法です。 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()

アプリと同じDBセットアップを使用しているため、実行するすべての単体テストでテストデータベースを構築および破棄できます。

15
AlexLordThorsen

Flask-Testingを使用したcodegeekの回答に関して、createapp()の機能を理解できません。 Flask-SqlAlchemy Introduction to Contexts は、SQLAlchemyオブジェクトをアプリケーションに動的にバインドする方法についてのポインタを提供してくれました。この場合、テストアプリケーションにバインドします。

基本的に:

  1. flask 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 Documentationで概説されているように、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オブジェクトを動的にバインドできることです。各アプリケーションは異なる目的に使用できます。たとえば、1つは本番用、もう1つは単体テスト用です。プロダクションの場合、最上位レベルでcreate_production_application()を呼び出すことができますflaskアプリケーション。

10
user2659443