【问题标题】:How to rollback database changes during Flask testing如何在 Flask 测试期间回滚数据库更改
【发布时间】:2018-04-10 12:27:35
【问题描述】:

在 pytest 中运行测试时,数据库被修改。撤消对数据库的更改的最佳方法是什么?

DBSession 回滚

对于那些我可以直接访问后端的测试,我目前使用 pytest 夹具为每个测试函数启动一个新的 DBSession,并在它结束时回滚会话

@pytest.fixture(scope='session')
def db(app, request):
    """Session-wide test database."""
    def teardown():
        pass

    _db = SQLAlchemy(app)    
    return _db

@pytest.fixture(scope='function')
def db_session(db, request):
    """Creates a new database session for a test."""
    engine = create_engine(
                            TestConfig.SQLALCHEMY_DATABASE_URI,
                            connect_args={"options": "-c timezone=utc"})
    DbSession = sessionmaker(bind=engine)
    session = DbSession()
    connection = engine.connect()
    transaction = connection.begin()
    options = dict(bind=connection, binds={})
    session = db.create_scoped_session(options=options)
    db.session = session

    yield session

    transaction.rollback()
    connection.close()
    session.remove()

在测试代码中,我只是简单的使用了fixture

def test_create_project(db_session): 项目 = _create_test_project(db_session) 断言 project.project_id > 0

Flask / HTTP 测试

但是为了通过 Flask/HTTP 测试 API,我不能使用 db_session。即使我创建一个夹具来显式地DROP 测试数据库并从生产中恢复,它也不会工作,因为没有直接的数据库代码

@pytest.fixture(scope='function')
def db_session_refresh(db, request):
    """Refresh the test database from production after running the test"""
    engine = create_engine(
                            TestConfig.SQLALCHEMY_DATABASE_URI,
                            connect_args={"options": "-c timezone=utc"})
    DbSession = sessionmaker(bind=engine)
    session = DbSession()

    connection = engine.connect()
    transaction = connection.begin()

    options = dict(bind=connection, binds={})
    session = db.create_scoped_session(options=options)

    db.session = session

    yield session

    transaction.rollback()
    connection.close()
    session.remove()  
    refresh_test_db_sql = """
        SELECT pg_terminate_backend(pid)
        FROM pg_stat_activity
        WHERE datname = 'appdb_test';

        DROP DATABASE appdb_test;

        CREATE DATABASE appdb_test TEMPLATE appdb;
        """
    engine.execute(refresh_test_db_sql)

即使这样可行,为每个函数刷新数据库也是低效的。

运行修改数据库的测试的正确/更好的方法是什么?

【问题讨论】:

  • 当然,您应该使用单独的数据库进行测试,而不是回滚主数据库。您在setUp 方法中建立一个数据库并在tearDown 中销毁。
  • 我确实有 dbappdbapp_test。运行 Flask HTTP 测试代码时如何回滚对数据库的更改?

标签: python flask sqlalchemy flask-sqlalchemy pytest


【解决方案1】:

如前所述 - 数据库的创建和销毁应从单元测试中处理出来并移至包装器中。

但要回答您的问题-我的印象是您正在使用 postgresql。尝试从连接字符串中删除数据库名称并直接连接到它并将其添加到search_path

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多