简体   繁体   English

Flask测试期间如何回滚数据库更改

[英]How to rollback database changes during Flask testing

When running tests in pytest, the database is modified. 在pytest中运行测试时,将修改数据库。 What is the best way to undo changes to the database? 撤消对数据库所做更改的最佳方法是什么?

DBSession rollback DBSession回滚

For those tests where I can access the backend directly, I currently use pytest fixture to start a new DBSession for every test function, and rollback the session at the end of it 对于那些可以直接访问后端的测试,我目前使用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()

In the test code, I simply use the fixture 在测试代​​码中,我只是使用夹具

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

Flask / HTTP Testing 烧瓶/ HTTP测试

But for testing the API via Flask/HTTP, I cannot use db_session . 但是为了通过Flask / HTTP测试API,我不能使用db_session Even when I create a fixture to explicitly DROP the test database and restore from production, it will not work because there is no direct database code 即使我创建了一个夹具来显式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)

Even if this works, it is inefficient to refresh the database for every function. 即使这可行,刷新每个函数的数据库效率也很低。

What is the proper/better way to run test that modifies the database? 运行修改数据库的测试的正确/更好的方法是什么?

as commented earlier - creation and destruction of the DB should be taken care out of you unit test and moved into a wrapper. 如前所述-在进行单元测试时,应该注意数据库的创建和销毁,并移入包装器中。

but to answer you question - I have the impression that you're using postgresql. 但要回答您的问题-我给您的印象是您使用的是postgresql。 try removing the database name from your connection string and connect to it directly and add it to the search_path 尝试从连接字符串中删除数据库名称,然后直接连接到数据库并将其添加到search_path

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM