无法在使用 pytest_postgresql 进行测试时在测试数据库中创建表格。

huangapple go评论97阅读模式
英文:

Can't create tables in test database while testing with pytest_postgresql

问题

我尝试编写一个使用 fixtures 和 pytest_postgresql 在 Postgres 中进行模型和数据库的 pytest 测试。

运行测试时出现了以下错误:

  1. FAILED tests/test_model_with_test_db.py::test_authors - sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "authors" does not exist

为什么它没有使用 model.Base.metadata.create_all(con) 创建所有表格?

我的测试代码如下:

  1. import pytest
  2. from pytest_postgresql import factories
  3. from pytest_postgresql.janitor import DatabaseJanitor
  4. from sqlalchemy import create_engine, select
  5. from sqlalchemy.orm.session import sessionmaker
  6. import model
  7. test_db = factories.postgresql_proc(port=None, dbname="test_db")
  8. @pytest.fixture(scope="session")
  9. def db_session(test_db):
  10. pg_host = test_db.host
  11. pg_port = test_db.port
  12. pg_user = test_db.user
  13. pg_password = test_db.password
  14. pg_db = test_db.dbname
  15. with DatabaseJanitor(pg_user, pg_host, pg_port, pg_db, test_db.version, pg_password):
  16. connection_str = f"postgresql+psycopg2://{pg_user}@{pg_host}:{pg_port}/{pg_db}"
  17. engine = create_engine(connection_str)
  18. with engine.connect() as con:
  19. model.Base.metadata.create_all(con)
  20. yield sessionmaker(bind=engine, expire_on_commit=False)
  21. @pytest.fixture(scope="module")
  22. def create_test_data():
  23. authors = [
  24. ["John", "Smith", "john@gmail.com"],
  25. ["Bill", "Miles", "bill@gmail.com"],
  26. ["Frank", "James", "frank@gmail.com"]
  27. ]
  28. return [model.Author(firstname=firstname, lastname=lastname, email=email)
  29. for firstname, lastname, email in authors]
  30. def test_persons(db_session, create_test_data):
  31. s = db_session()
  32. for obj in create_test_data:
  33. s.add(obj)
  34. s.commit()
  35. query_result = s.execute(select(model.Author)).all()
  36. s.close()
  37. assert len(query_result) == len(create_test_data)

model.py:

  1. from sqlalchemy import create_engine, Column, Integer, String, DateTime, Text, ForeignKey
  2. from sqlalchemy.engine import URL
  3. from sqlalchemy.orm import declarative_base, relationship, sessionmaker
  4. from datetime import datetime
  5. Base = declarative_base()
  6. class Author(Base):
  7. __tablename__ = 'authors'
  8. id = Column(Integer(), primary_key=True)
  9. firstname = Column(String(100))
  10. lastname = Column(String(100))
  11. email = Column(String(255), nullable=False)
  12. joined = Column(DateTime(), default=datetime.now)
  13. articles = relationship('Article', backref='author')
  14. class Article(Base):
  15. __tablename__ = 'articles'
  16. id = Column(Integer(), primary_key=True)
  17. slug = Column(String(100), nullable=False)
  18. title = Column(String(100), nullable=False)
  19. created_on = Column(DateTime(), default=datetime.now)
  20. updated_on = Column(DateTime(), default=datetime.now, onupdate=datetime.now)
  21. content = Column(Text)
  22. author_id = Column(Integer(), ForeignKey('authors.id'))
  23. url = URL.create(
  24. drivername="postgresql",
  25. username="postgres",
  26. host="localhost",
  27. port=5433,
  28. database="andy"
  29. )
  30. engine = create_engine(url)
  31. Session = sessionmaker(bind=engine)

(请注意,我已经修复了代码中的 HTML 转义字符,以便正确显示代码部分。)

英文:

I'm trying to write a pytest for models and database in Postgres using fixtures and pytest_postgresql.

Running test gives:

  1. FAILED tests/test_model_with_test_db.py::test_authors - sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "authors" does not exist

Why it doesn't created all tables with model.Base.metadata.create_all(con)?

My test code is following:

  1. import pytest
  2. from pytest_postgresql import factories
  3. from pytest_postgresql.janitor import DatabaseJanitor
  4. from sqlalchemy import create_engine, select
  5. from sqlalchemy.orm.session import sessionmaker
  6. import model
  7. test_db = factories.postgresql_proc(port=None, dbname="test_db")
  8. @pytest.fixture(scope="session")
  9. def db_session(test_db):
  10. pg_host = test_db.host
  11. pg_port = test_db.port
  12. pg_user = test_db.user
  13. pg_password = test_db.password
  14. pg_db = test_db.dbname
  15. with DatabaseJanitor(pg_user, pg_host, pg_port, pg_db, test_db.version, pg_password):
  16. connection_str = f"postgresql+psycopg2://{pg_user}:@{pg_host}:{pg_port}/{pg_db}"
  17. engine = create_engine(connection_str)
  18. with engine.connect() as con:
  19. model.Base.metadata.create_all(con)
  20. yield sessionmaker(bind=engine, expire_on_commit=False)
  21. @pytest.fixture(scope="module")
  22. def create_test_data():
  23. authors = [
  24. ["John", "Smith", "john@gmail.com"],
  25. ["Bill", "Miles", "bill@gmail.com"],
  26. ["Frank", "James", "frank@gmail.com"]
  27. ]
  28. return [model.Author(firstname=firstname, lastname=lastname, email=email)
  29. for firstname, lastname, email in authors]
  30. def test_persons(db_session, create_test_data):
  31. s = db_session()
  32. for obj in create_test_data:
  33. s.add(obj)
  34. s.commit()
  35. query_result = s.execute(select(model.Author)).all()
  36. s.close()
  37. assert len(query_result) == len(create_test_data)

model.py:

  1. from sqlalchemy import create_engine, Column, Integer, String, DateTime, Text, ForeignKey
  2. from sqlalchemy.engine import URL
  3. from sqlalchemy.orm import declarative_base, relationship, sessionmaker
  4. from datetime import datetime
  5. Base = declarative_base()
  6. class Author(Base):
  7. __tablename__ = 'authors'
  8. id = Column(Integer(), primary_key=True)
  9. firstname = Column(String(100))
  10. lastname = Column(String(100))
  11. email = Column(String(255), nullable=False)
  12. joined = Column(DateTime(), default=datetime.now)
  13. articles = relationship('Article', backref='author')
  14. class Article(Base):
  15. __tablename__ = 'articles'
  16. id = Column(Integer(), primary_key=True)
  17. slug = Column(String(100), nullable=False)
  18. title = Column(String(100), nullable=False)
  19. created_on = Column(DateTime(), default=datetime.now)
  20. updated_on = Column(DateTime(), default=datetime.now, onupdate=datetime.now)
  21. content = Column(Text)
  22. author_id = Column(Integer(), ForeignKey('authors.id'))
  23. url = URL.create(
  24. drivername="postgresql",
  25. username="postgres",
  26. host="localhost",
  27. port=5433,
  28. database="andy"
  29. )
  30. engine = create_engine(url)
  31. Session = sessionmaker(bind=engine)

答案1

得分: 2

Figured out myself.
Modified db_session fixture like following:

  1. @pytest.fixture(scope="session")
  2. def db_session(test_db):
  3. pg_host = test_db.host
  4. pg_port = test_db.port
  5. pg_user = test_db.user
  6. pg_password = test_db.password
  7. pg_db = test_db.dbname
  8. with DatabaseJanitor(pg_user, pg_host, pg_port, pg_db, test_db.version, pg_password):
  9. connection_str = f"postgresql+psycopg2://{pg_user}:{pg_password}@{pg_host}:{pg_port}/{pg_db}"
  10. engine = create_engine(connection_str)
  11. model.Base.metadata.create_all(engine)
  12. yield sessionmaker(bind=engine, expire_on_commit=False)

And test passes.

But why it doesn't work with connection instead?

英文:

Figured out myself.
Modified db_session fixture like following:

  1. @pytest.fixture(scope="session")
  2. def db_session(test_db):
  3. pg_host = test_db.host
  4. pg_port = test_db.port
  5. pg_user = test_db.user
  6. pg_password = test_db.password
  7. pg_db = test_db.dbname
  8. with DatabaseJanitor(pg_user, pg_host, pg_port, pg_db, test_db.version, pg_password):
  9. connection_str = f"postgresql+psycopg2://{pg_user}:@{pg_host}:{pg_port}/{pg_db}"
  10. engine = create_engine(connection_str)
  11. model.Base.metadata.create_all(engine)
  12. yield sessionmaker(bind=engine, expire_on_commit=False)

And test passes.

But why it doesn't work with connection instead?

huangapple
  • 本文由 发表于 2023年6月13日 02:46:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76459471.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定