分别使用内存数据库进行测试 - 如何?

时间:2016-02-18 23:34:30

标签: python flask sqlalchemy flask-sqlalchemy flask-testing

我有这段代码:

my_app.py:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

import os

app = Flask(__name__)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["BASE_DIR"] = os.path.abspath(os.path.dirname(__file__))
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.abspath(os.path.join(app.config["BASE_DIR"], "app.db"))

db = SQLAlchemy(app)

from user import User

# create all tables
db.create_all()

if not User.query.filter_by(username="test").first():
    dummy_user = User(username="test", password="", email="")
    db.session.add(dummy_user)
    db.session.commit()

user.py:

from flask.ext.login import UserMixin

from my_app import db


class User(db.Model):
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), nullable=False, unique=True)
    email = db.Column(db.String(255), nullable=False, unique=True)
    password = db.Column(db.String(255), nullable=False)

tests.py:

from flask.ext.testing import TestCase
from my_app import app, db
from user import User

import os
import unittest


class MyTestCase(TestCase):
    def create_app(self):
        app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
        app.config["TESTING"] = True
        return app

    def setUp(self):
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()

    def test_dummy(self):
        assert User.query.count() == 0

if __name__ == '__main__':
    unittest.main()

如何使单元测试工作?

我希望我的单元测试使用与主应用程序分开的内存数据库,但显然我不能按照我尝试的方式(仅通过更改SQLALCHEMY_DATABASE_URI值)来实现

提前致谢!

3 个答案:

答案 0 :(得分:0)

好的,所以我找到了解决方案,或者更确切地说是解决方法:

我使用环境变量来指定在初始化db实例之前加载的其他配置文件。

所以我最终这样做了:

app.config.from_object("app.config.production")
additional_config = os.environ.get("ADDITIONAL_CONFIG")
if additional_config:
    app.config.from_object(additional_config)

在我的my_app.py中,这在我的tests.py中:

os.environ["ADDITIONAL_CONFIG"] = "app.config.testing"

from my_app import app, db

(在导入app对象之前定义环境变量当然很重要)

非常感谢。

答案 1 :(得分:0)

听起来像是继承配置的完美案例!

您是否尝试过使用找到的here模板? Config基类包含所有不同环境通用的设置。但是,您可以拥有一个使用内存数据库的开发环境。例如:

class Config:
  # pass

class DevConfig(Config):
  SQLALCHEMY_DATABASE_URI = 'sqlite://path_to_in_memory_db'

class ProductionConfig(Config):
  SQLALCHEMY_DATABASE_URI = 'postgresql://path_to_production_db'

使用factory pattern创建应用也值得考虑。

答案 2 :(得分:0)

我使用环境变量通过pytest选择数据库。在使用docker-compose为生产人员指定生产数据库而非sqllite时,此方法效果很好。

# app.py
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
DATABASE = os.environ.get("DB_URI", f"sqlite:///{os.path.join(BASE_DIR, 'app.db')}")

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = DATABASE

然后在导入应用程序或数据库之前,在test.py中注入DB_URI环境变量以指定内存数据库:

import pytest
import os

os.environ['DB_URI'] = "sqlite:///:memory:"
from app import app, db
from models import Model1, Model2


@pytest.fixture
def client():
    client = app.test_client()

    with app.app_context():
        db.create_all()
        prepare_data()
    yield client

    db.drop_all()