如何正确构建 SQLAlchemy(声明式)python 项目及其单元测试

Saš*_*jak 7 python testing unit-testing sqlalchemy

我正在为一些网络应用程序开发大型后端。这是我的第一个 python 和 SQLAlchemy 项目,所以我对一些事情感到困惑。与 python 相比,有点被 Java 编程工具和 IDE 宠坏了(反正我在 eclipse 中使用 pydev)。我需要有关如何构建项目和编写测试的帮助。我先描述一下情况。

在 PyDev 中,我将我的项目命名为“ProjectName”,下面我显示了我当前的文件夹/包和文件结构。

  • 项目名
    • 项目名
      • __init__.py
      • some_package
        • __init__.py
        • 文件
        • 酒吧.py
    • 测试
      • 单元测试
        • __init__.py
        • some_package
          • __init__.py
          • 测试文件
          • 测试条
      • 负载测试
      • 集成测试
      • __init__.py

我在 SQLAlchemy 中使用声明式风格。Foo 和 Bar 是一些类,例如 Foo 扩展 SQLAlchemy 声明性 Base 和 Bar 扩展 Foo。在它的 __init__.py 中的“projectname.some_package”下,我有以下代码:

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

因此,Foo 导入此 Base 并扩展它,而 Bar 导入 Foo 并扩展它。我的第一个问题是,我应该将 Base 存储在 __init__.py 中并像我开始使用这两个类一样使用它吗?这个 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()
Run Code Online (Sandbox Code Playgroud)

结束然后我在该测试类中有一些测试方法并且它运行良好。在 TestBar 类中的区别在于

Foo.metadata.create_all(bind=self.engine)
Run Code Online (Sandbox Code Playgroud)

是 :

Bar.metadata.create_all(bind=self.engine)
Run Code Online (Sandbox Code Playgroud)

当我运行 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)
Run Code Online (Sandbox Code Playgroud)

这里有什么问题?我试图用鼻子和 pydev 跑步者运行测试并得到相同的错误。然后我尝试在 unit_tests 下的 some_package 中的 __init__.py 中移动数据库表的创建,但我无法让它工作。另外,我对 python 导入的工作方式感到困惑。例如,如果我在 TestBar 类中添加 Foo 导入,我也会收到与我已经显示的类似的错误。如何一次运行多个单元测试来测试 SQLAlchemy 类?

所以再次提取最重要的问题:

  1. 如何构建正确使用 SQLAlchemy 声明式样式和单元测试的 python 项目。顺便说一句,我在 Foo 和 Bar 中有许多与数据库交互的类方法,在它们各自的类的上下文中,我希望可以吗?
  2. 在哪里存储 Base 声明性类以及如何在整个项目中正确使用它,以及如何在项目中的任何位置提取所有数据库模式(我在我的类中声明性定义的)并使用它?
  3. 如何最好地使用 SQLAlchemy 的单元测试并一次运行多个单元测试?
  4. 如果您有任何其他建议,请随时添加它?

非常感谢你的帮助。

Wic*_*man 4

快速回答(抱歉,时间不够):使用单个 MetaData 实例,而不是 Foo 和 Bar 都使用一个实例。一般来说,多个 MetaData 实例是一种您几乎不需要的高级技巧。