使用PostgreSQL在SQLAlchemy测试中创建数据库

时间:2015-04-08 06:49:59

标签: python postgresql sqlalchemy pyramid pytest

我正在构建一个构建在SQLAlchemy顶部的Pyramid Web应用程序,并且只依赖PostgreSQL作为其数据库后端。

有什么方法可以让单元测试结构

  • 数据库在每次测试运行时构建一次 - 而不是在每个测试setUp()上构建,因为这对于复杂的应用来说太慢了

  • 创建数据库表(因为它们将在生产中创建)(例如,从Alembic运行迁移)。在测试运行开始时,任何不干净的数据库都会被销毁。

  • 如果标准库unittest框架之外的特定功能可以更轻松地编写测试用例,则可以选择自定义测试运行程序la py.test

1 个答案:

答案 0 :(得分:5)

Nose测试运行器支持setup_package()teardown_package()方法。以下是文档的摘录:

  

Test Packages

     

nose允许将测试分组到测试包中。这允许   包级设置;例如,如果您需要创建测试   您可以在其中创建测试的数据库或其他数据夹具   软件包设置并在每次测试运行时将其删除一次   而不是每个测试模块或者必须创建和拆除它一次   测试用例。

     

要创建包级别设置和拆卸方法,请定义设置   和/或拆解测试包的 init .py中的函数。建立   方法可以命名为setup,setup_package,setUp或setUpPackage;   拆解可能被命名为拆解,拆卸,拆卸或拆卸   tearDownPackage。测试包中的测试执行很快就会开始   因为第一个测试模块是从测试包中加载的。

在我的应用程序中,我有setup_package(),大致如下所示:

def _create_database():

    template_engine = sa.create_engine("postgres://postgres@/postgres", echo=False)

    conn = template_engine.connect()
    conn = conn.execution_options(autocommit=False)
    conn.execute("ROLLBACK")
    try:
        conn.execute("DROP DATABASE %s" % DB_NAME)
    except sa.exc.ProgrammingError as e:
        # Could not drop the database, probably does not exist
        conn.execute("ROLLBACK")
    except sa.exc.OperationalError as e:
        # Could not drop database because it's being accessed by other users (psql prompt open?)
        conn.execute("ROLLBACK")

    conn.execute("CREATE DATABASE %s" % DB_NAME)
    conn.close()

    template_engine.dispose()


def setup_package():
    _create_database()

    engine = sa.create_engine("postgres://postgres@/%s" % DB_NAME, echo=False)

    session = sa.orm.scoped_session(sa.orm.sessionmaker())
    session.configure(bind=engine)
    Base.metadata.bind = engine
    Base.metadata.create_all()


def teardown_package():
    # no need to do anything as the old database is dropped at the start of every run

此外,所有测试用例类都是从基类创建的子类,重要的是,它定义了一个通用的tearDown方法:

class BaseTest(unittest.TestCase):

    def setUp(self):
        # This makes things nicer if the previous test fails
        # - without this all subsequent tests fail
        self.tearDown()

        self.config = testing.setUp()

    def tearDown(self):
        testing.tearDown()
        session.expunge_all()
        session.rollback()

子类通常会覆盖基类setUp,但通常不需要重写tearDown - 通过回滚事务,它确保下一个测试将在完全干净的数据库上启动。