python 使用pytest-postgresql的第二次测试仍然使用第一次测试的模式

q3qa4bjr  于 2023-05-05  发布在  Python
关注(0)|答案(1)|浏览(117)

我尝试使用pytest-postgresql执行一些测试,但似乎我没有完全掌握从fixture生成的引擎如何工作。下面的代码是我可以编写的最小示例,以重现我得到的错误。有两个测试分别以tokyo和伦敦命名,每个测试都使用DB连接创建一个以城市名称命名的模式,然后在模式中创建表citymeta

import pytest
from pytest_postgresql.janitor import DatabaseJanitor
from sqlalchemy import create_engine, inspect
from sqlalchemy.orm import Session
from sqlalchemy import text
from sqlalchemy import (Column, Integer, String)
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class BaseModel(Base):
    __abstract__ = True
    id = Column(Integer, primary_key=True)

class CityMeta(BaseModel):
    __tablename__ = "citymeta"
    id = Column(Integer, primary_key=True)
    version = Column(String(10), nullable=False)

def create_table(engine, schema):
    with engine.connect() as conn:
        conn.execute(text(f"""CREATE SCHEMA IF NOT EXISTS
                                {schema}"""))
        conn.commit()

    for table in BaseModel.metadata.tables.values():
        table.schema = schema
        table.create(engine, checkfirst=True)

schema1 = "tokyo"
schema2 = "london"

@pytest.fixture(scope="session")
def engine_postgresql(postgresql_proc):
    with DatabaseJanitor(
        postgresql_proc.user,
        postgresql_proc.host,
        postgresql_proc.port,
        postgresql_proc.dbname,
        postgresql_proc.version,
        password=postgresql_proc.password,
    ):
        yield create_engine(
            f"postgresql+psycopg2://{postgresql_proc.user}:"
            f"{postgresql_proc.password}@{postgresql_proc.host}:"
            f"{postgresql_proc.port}/{postgresql_proc.dbname}"
        )

def test_tokyo(engine_postgresql):
    create_table(engine_postgresql, schema1)
    insp = inspect(engine_postgresql)
    assert insp.has_table("citymeta", schema=schema1)

    with Session(engine_postgresql) as session:
        meta = CityMeta(id=1, version='2.3')
        session.add(meta)
        session.commit()
        res = session.query(CityMeta).filter_by(id=1).first()
        assert res.version == '2.3'

def test_london(engine_postgresql):
    create_table(engine_postgresql, schema2)
    insp = inspect(engine_postgresql)
    assert insp.has_table("citymeta", schema=schema2)

    with Session(engine_postgresql) as session:
        meta = CityMeta(id=1, version='0.0')
        session.add(meta)
        session.commit()
        res = session.query(CityMeta).filter_by(id=1).first()
        assert res.version == '0.0'

因为每个测试都创建了一个单独的模式,所以我希望这两个测试都能正常运行。但是,我在第二次测试中得到以下错误:

sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "citymeta_pkey"
E       DETAIL:  Key (id)=(1) already exists.
E       
E       [SQL: INSERT INTO tokyo.citymeta (id, version) VALUES (%(id)s, %(version)s)]
E       [parameters: {'id': 1, 'version': '0.0'}]
E       (Background on this error at: https://sqlalche.me/e/20/gkpj)

看起来在第二个测试(伦敦)中,即使london模式成功创建,当会话启动时,它仍然使用模式tokyo,并且由于密钥冲突(两个id都是1)而无法插入数据。我知道pytest-postgresql在测试结束前维护着同一个数据库,但是,由于在第二个测试中生成了一个新的模式,新的会话不应该使用这个新的模式吗?

dz6r00yl

dz6r00yl1#

受到this question的答案的启发,我在第二个测试中添加了这行代码来运行测试:

engine_postgresql.update_execution_options(schema_translate_map={None: schema2})

相关问题