简体   繁体   English

Python 测试:从 Pytest 固定装置播种数据库

[英]Python Testing: Seeding a database from Pytest fixture

I am currently trying to follow a wonderful tutorial around setting up and tearing down databases in a testing environment.我目前正在尝试遵循一个关于在测试环境中设置和拆除数据库的精彩教程 Everything works well except for the seed_database() call which throws the following error.除了引发以下错误的seed_database()调用外,一切都运行良好。

AttributeError: 'function' object has no attribute 'add'

Some questions:一些问题:

  1. Why is db_session even defined when I run seed_database ?为什么在我运行db_session时甚至定义了seed_database It's not being passed in anywhere... My initial guess was that it has something to do with the way Python fixtures work, but it seems a little magical.它没有被传递到任何地方......我最初的猜测是它与 Python 固定装置的工作方式有关,但它似乎有点神奇。
  2. What changes can I make for db_session to actually be a proper scoped_session?我可以对db_session进行哪些更改才能真正成为正确的 scoped_session?

test_config.py

@pytest.fixture(scope="session")
def connection():
    engine = create_engine(
        "mysql+mysqldb://{}:{}@{}:{}/{}".format(
            os.environ.get('TEST_DB_USER'),
            os.environ.get('TEST_DB_PASSWORD'),
            os.environ.get('TEST_DB_HOST'),
            os.environ.get('TEST_DB_PORT'),
            os.environ.get('TEST_DB_NAME'),
        )
    )
    return engine.connect()


def seed_database():
    users = [
        {
            "id": 1,
            "name": "John Doe",
        },
        # ...
    ]

    for user in users:
        db_user = User(**user)
        db_session.add(db_user)
    db_session.commit()


@pytest.fixture(scope="session")
def setup_database(connection):
    models.Base.metadata.bind = connection
    models.Base.metadata.create_all()
    
    seed_database()

    yield

    models.Base.metadata.drop_all()


@pytest.fixture
def db_session(setup_database, connection):
    transaction = connection.begin()
    yield scoped_session(
        sessionmaker(autocommit=False, autoflush=False, bind=connection)
    )
    transaction.rollback()

test_user.py

from tests.test_config import db_session, setup_database, connection

def test_something(db_session):
    # Some code here...

Why is db_session even defined when I run seed_database?为什么在我运行seed_database 时甚至定义了db_session?

In Python functions are objects like other.在 Python 中,函数是像其他对象一样的对象。 Hence the 'function' object in the error message.因此错误消息中的“函数”对象 db_session is defined in the module and therefore is accessible within seed_database . db_session在模块中定义,因此可以在seed_database中访问。 The only "magic" is that you actually cannot call db_session because Pytest fixtures cannot be called directly.唯一的“魔力”是您实际上无法调用db_session ,因为无法直接调用 Pytest 固定装置。

What changes can I make for db_session to actually be a proper scoped_session?我可以对 db_session 进行哪些更改才能真正成为正确的 scoped_session?

I think that you might have a "chicken and egg" situation: db_session uses setup_database fixture which calls seed_database which requires db_session to already return the session.我认为您可能会遇到“鸡和蛋”的情况: db_session使用setup_database固定装置,它调用了需要seed_database已经返回会话的db_session You would need to reorganise the code to get out of this.您需要重新组织代码才能摆脱这种情况。

Without being familiar with the database sessions that you are using it's a bit of a guess work for me but maybe something like this would work:在不熟悉您正在使用的数据库会话的情况下,这对我来说有点猜测,但也许这样的事情会起作用:

def seed_database(db_session):
    users = [
        {
            "id": 1,
            "name": "John Doe",
        },
        # ...
    ]

    for user in users:
        db_user = User(**user)
        db_session.add(db_user)

    db_session.commit()

@pytest.fixture
def db_session(setup_database, connection):
    transaction = connection.begin()
    session = scoped_session(
        sessionmaker(autocommit=False, autoflush=False, bind=connection)
    )
    seed_database(db_session=session)
    yield session
    transaction.rollback()

...and you would remove seed_database() call from setup_database . ...并且您将从setup_database中删除seed_database()调用。

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

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