Как правильно структурировать SQLAlchemy (декларативный стиль) Python проект и его юнит-тесты - PullRequest
3 голосов
/ 09 февраля 2012

Я разрабатываю большой бэкэнд для некоторых веб-приложений.Это мой первый проект на Python и SQLAlchemy, поэтому меня смущают некоторые вещи.И был отчасти испорчен инструментами программирования Java и IDE по сравнению с python (я все равно использую pydev в eclipse).Мне нужна помощь с тем, как структурировать проект и написать тесты.Сначала я опишу ситуацию.

В PyDev я назвал мой проект, например, «ProjectName», а ниже я показал мою текущую папку / пакет и структуру файлов.

  • ProjectName
    • имя проекта
      • __ init __. Py
      • some_package
        • __ init __. Py
        • Foo.py
        • Bar.py
    • тесты
      • unit_tests
        • __ init __. py
        • some_package
          • __ init __. py
          • TestFoo.py
          • TestBar.py
      • load_tests
      • gration_tests
      • __ init __. Py

Я использую декларативный стиль в SQLAlchemy.Foo и Bar - это некоторые классы, например, Foo расширяет декларативную базу SQLAlchemy, а Bar расширяет Foo.Под 'projectname.some_package' в __init__.py у меня есть этот код:

engine = create_engine('mysql+mysqldb://user:pass@localhost:3306/SomeDataBase', pool_recycle=3600)
Session = sessionmaker(bind=engine)
Base = declarative_base()

Итак, Foo импортирует эту базу и расширяет ее, а Bar импортирует Foo и расширяет ее.Мой первый вопрос: должен ли я хранить Base в этом __init__.py и использовать его так, как я начал с этих 2 классов?Это create_engine просто временно, я хотел бы иметь конфигурационный файл и загрузить его настройки оттуда, как это сделать?Где я должен вызвать Base.metadata.create_all (), чтобы он мог создавать все таблицы базы данных одновременно?

Далее, в классах тестирования, например в TestFoo, у меня есть этот код:

def setUp(self):
    #create database tables and session object
    self.engine = create_engine('mysql+mysqldb://user:pass@localhost:3306/SomeDatabase', pool_recycle=3600)
    Session = sessionmaker(bind=self.engine)
    Foo.metadata.create_all(bind=self.engine)
    self.session = Session()

def tearDown(self):
    #drop all tables and close session object
    self.session.close()
    meta = MetaData(self.engine)
    meta.reflect()
    meta.drop_all()

Конец, тогда у меня есть несколько тестовых методов в этом тестовом классе, и он работает нормально.В классе TestBar разница в том, что

Foo.metadata.create_all(bind=self.engine)

:

Bar.metadata.create_all(bind=self.engine)

Когда я запускаю TestBar, он также работает нормально.Но когда я выбираю оба тестовых класса и запускаю их, я получаю ошибки:

/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative.py:1336: SAWarning: The classname 'Foo' is already in the registry of this declarative base, mapped to <class 'projectname.some_package.Foo.Foo'>
  _as_declarative(cls, classname, cls.__dict__)
/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py:330: Warning: Field 'id' doesn't have a default value
 cursor.execute(statement, parameters)

В чем здесь проблема?Я пытался запустить тесты с носовыми и пидевскими бегунами и получал те же ошибки.Затем я попытался переместить создание таблиц базы данных в __init__.py в some_package в unit_tests, но не смог заставить его работать.Кроме того, я запутался в том, как работает импорт python.Например, если я добавляю импорт Foo в класс TestBar, я также получаю ошибки, подобные тем, что я уже показал.Как я могу запустить много модульных тестов, которые одновременно тестируют классы SQLAlchemy?

Итак, чтобы снова извлечь наиболее важные вопросы:

  1. Как структурировать проект Python, который использует декларативный стиль SQLAlchemy июниттесты правильно.Кстати, у меня есть много методов классов в Foo и Bar, которые взаимодействуют с базой данных, в контексте их соответствующих классов, я надеюсь, что это нормально?
  2. Где хранить декларативный класс Base и как правильно использовать его во всем проекте, и как извлечь всю схему базы данных (которую я определенно определил в моих классах) в любом месте проекта и использовать ее?
  3. Как лучше всего использовать юнит-тесты с SQLAlchemy и запускать несколько юнит-тестов одновременно?
  4. Если у вас есть какие-либо другие предложения, не стесняйтесь добавлять его?

Большое спасибо за помощь.

1 Ответ

2 голосов
/ 10 февраля 2012

Быстрый ответ (не хватает времени, извините): используйте один экземпляр MetaData вместо одного для Foo и Bar.В целом, несколько экземпляров метаданных - это продвинутый трюк, который вам почти никогда не нужен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...