【问题标题】:MongoEngine connects to incorrect database during testingMongoEngine 在测试期间连接到错误的数据库
【发布时间】:2019-06-03 15:37:04
【问题描述】:

上下文

我正在创建Flask 应用程序连接到mongodb 使用MongoEngine 通过flask-mongoengine 扩展。我按照configuration 说明中的说明使用application factory pattern 创建我的应用程序。

问题

在运行测试时,我指定了名为datazilla_test 的测试数据库,它通过mongo.init_app(app) 传递给mongo 实例。即使我的app.config['MONGODB_DB']mongo.app.config['MONGODB_DB'] 实例具有正确的值(datazilla_test),该值也不会反映在mongo 实例中。因此,当我运行断言assert mongo.get_db().name == mongo.app.config['MONGODB_DB'] 时,会触发此错误AssertionError: assert 'datazzilla' == 'datazzilla_test'

问题

我做错了什么?为什么数据库连接持续使用默认数据库datazzilla,而不是datazilla_test?如何解决?

源代码

# __init__.py
from flask_mongoengine import MongoEngine

mongo = MongoEngine()


def create_app(config=None):
    app = Flask(__name__)

    app.config['MONGODB_HOST'] = 'localhost'
    app.config['MONGODB_PORT'] = '27017'
    app.config['MONGODB_DB'] = 'datazzilla'

    # override default config
    if config is not None:
        app.config.from_mapping(config)

    mongo.init_app(app)

    return app
# conftest.py
import pytest
from app import mongo
from app import create_app


@pytest.fixture
def app():
    app = create_app({
        'MONGODB_DB': 'datazzilla_test',
    })

    assert mongo.get_db().name == mongo.app.config['MONGODB_DB']
    # AssertionError: assert 'datazzilla' == 'datazzilla_test'

    return app

【问题讨论】:

  • 听起来您的全局mongo 实例在您的夹具被调用之前已经连接到“datazzilla”数据库。您能否在create_app 调用之前调用mongo.get_db() 并让我知道结果(如果没有建立其他连接,它应该引发 MongoEngineConnectionError)
  • 我按照你的建议做了。在create_app 之前调用mongo.get_db() 的结果是db 连接指向datazzilla db。

标签: mongodb flask pytest mongoengine flask-mongoengine


【解决方案1】:

Mongoengine 在调用您的夹具时已经连接,当您从夹具调用 app = create_app 时,它会尝试重新建立连接但静默失败(因为它看到已建立现有的默认连接)。

这在 mongoengine 的开发版本中进行了重新设计(请参阅 https://github.com/MongoEngine/mongoengine/pull/2038),但尚未发布(截至 2019 年 6 月 4 日)。当该版本发布时,您将能够通过调用 disconnect_all 断开任何现有的 mongoengine 连接

与此同时,您可以: - 检查现有连接的创建位置并阻止它 - 尝试使用以下方法断开现有连接:

from mongoengine.connection import disconnect, _connection_settings

@pytest.fixture
def app():
    disconnect()
    del _connection_settings['default']
    app = create_app(...)
    ...

但它可能有其他副作用

【讨论】:

  • 谢谢,成功了!到目前为止,我还没有遇到任何副作用,因此我赞成这个问题:) 我期待看到 mongoengine 版本 > 0.17.0 并测试disconnect_all。附言我的 mongoclient 抛出此警告 MongoClient opened before fork. Create MongoClient only after forking. 您是否知道这种行为并知道如何解决它?
  • P.S.2 我找到了 UserWarning: MongoClient opened before fork. 的解决方案,我不得不将 mongo 客户端上的连接属性从 true(默认)更改为 false。例如MongoClient(connect=False)
  • 听起来你在建立Mongoengine连接后分叉进程
【解决方案2】:

上下文

巧合的是,我想出了解决这个问题的办法。 @bagerard 的答案是正确的!它适用于MongoClient,其中客户端的连接设置为True - 这是/应该是默认值。

MongoClient(host=['mongo:27017'], document_class=dict, tz_aware=False, connect=False, read_preference=Primary())

如果是这种情况,那么您必须disconnect database and delete connection settings @bagerard 解释。

解决方案

但是,如果您将MongoClient 连接更改为False,则您不必断开数据库并删除连接设置。最终对我有用的解决方案就是这个解决方案。

def create_app(config=None):
    ...
    app.config['MONGODB_CONNECT'] = False
    ...

注意事项

正如我之前写的。我偶然发现了这个解决方案,我试图解决这个问题MongoClient opened before fork. Create MongoClient only after forking。事实证明它解决了这两个问题:)

P.S 如果有任何副作用,我现在还不知道!如果你找到了一些,请在 cmets 部分分享。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 2016-12-20
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    相关资源
    最近更新 更多