假设我正在关注Flask-SQLAlchemy快速启动示例,并且我想添加几个单元测试。
我的模型可能类似于:
db = SQLAlchemy(app)
Base = db.Model
class Account(Base):
id = Column(Integer, primary_key=True)
name = Column(String(1000))
对于单元测试,我想要为每个测试创建和销毁数据库。
def _setup_database():
db_name = 'test_%s' % random.randint(0,999999)
# (Code that creates database with db_name and setups the schema)
app.config['DB_NAME'] = db_name
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///{}'.format(db_name)
def _destroy_db():
db_name = app.config['DB_NAME']
# Code that destroys the test db
class TestAccounts(unittest.TestCase):
def setUp(self):
_setup_database()
def tearDown(self):
_destroy_db()
def test_new_signup(self):
account = models.Account(...)
def test_something_else(self):
account = models.Account(...)
这里的问题是,如果我在单元测试是多线程的环境中运行此代码,则存在竞争条件。通常同时设置两个数据库,并将app.config指向其中一个。
如果我直接使用SQLAlchemy,我会为每个测试创建一个新会话并使用该会话。但Flask-SQLAlchemy为我创建了会话,因此,似乎依赖于有一个全局app.config['SQLALCHEMY_DATABASE_URI']
指向数据库。
使用Flask-SQLAlchemy创建测试数据库并将测试线程指向它们的正确方法是什么?
答案 0 :(得分:3)
对于每个TestCase.setUp
函数运行unittest TestCase.tearDown
和test_
。
因此,在多线程进程中运行测试确实会创建一个RC。您需要在单个线程中运行测试。这将修复RC,但您仍然会为每个测试创建并销毁所有数据库,这是不必要的和缓慢的。
更好的解决方案是使用setUpclass
and tearDownClass
方法,每个测试类只运行一次。
如果您需要为模块中的所有类运行此灯具,还有setUpModule
和tearDownModule
。
如果你现在需要为整个会话设置灯具你有问题...恕我直言,是时候切换到pytest。