搭建Django测试环境时如何创建外部数据库?

Posted

技术标签:

【中文标题】搭建Django测试环境时如何创建外部数据库?【英文标题】:How to create an external database when setting up Django test environment? 【发布时间】:2016-02-17 09:57:54 【问题描述】:

我的 Django 应用程序需要连接一个非托管(非 Django)外部 Postgres 数据库。

为了测试我的项目,我需要使用原始 SQL 创建外部数据库和表,然后删除数据库。

通过阅读 Django 文档,可以使用现有的 DiscoverRunner 类创建您自己的 TestRunner 类。可以重写 setup_test_environmentteardown_test_environment 方法以执行 SQL 以创建外部数据库:

from psycopg2 import connect
from django.test.runner import DiscoverRunner

class CustomTestRunner(DiscoverRunner):
    """
    Test runner that helps to setup external db if doesn`t exist.
    """

    def setup_test_environment(self, *args, **kwargs):
        conn = connect(database='postgres', host='localhost', user='my_user', password='password123')
        try:
            with conn.cursor() as c:
                query = """CREATE DATABASE "test_db" """
                query += """WITH OWNER = my_user """
                query += """ENCODING = 'UTF8' TABLESPACE = pg_default """
                query += """LC_COLLATE = 'en_ZA.UTF-8' LC_CTYPE = 'en_ZA.UTF-8' """
                query += """CONNECTION LIMIT = -1;"""
                c.execute(query)
        except Exception as e:
            print e
            conn.close()

        super(CustomTestRunner, self).setup_test_environment(*args,
            **kwargs)

    def teardown_test_environment(self, *args, **kwargs):
        super(CustomTestRunner, self).teardown_test_environment(*args,
            **kwargs)

        # Delete external database after tests
        try:
            conn = connect(database='postgres', host='localhost', user='my_user', password='password123')
            with conn.cursor() as c:
                query = """DROP DATABASE test_db;"""
                c.execute(query)
        except Exception as e:
            print e
            conn.close()
        conn.close()

但是,当我运行测试时,我收到以下错误消息:

CREATE DATABASE cannot run inside a transaction block

是否可以在 Django TestRunner 中运行和提交 SQL?如果没有,在哪里创建这样一个外部数据库的合适位置?

【问题讨论】:

【参考方案1】:

某些数据库命令(例如 CREATE DATABASE)无法在事务中运行。您需要在数据库连接上设置适当的隔离级别:

conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)

见http://initd.org/psycopg/docs/extensions.html#isolation-level-constants。

还可以在测试运行程序中运行和提交 SQL。更合适的地方是setup_databsesteardown_databases 方法。这是一个例子

def setup_databases(self, **kwargs):
    conn = connect(database='postgres', host='localhost', ...)
    try:        
        # set the proper isolation level so CREATE DATABASE works
        conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
        with conn.cursor() as cur:
            # execute SQL in here
            query = 'create database TEST_DB'
            cur.execute(query)
    finally:
        conn.close()

    return super(CustomTestRunner, self).setup_databases(**kwargs)

teardown_databases 的实现应该非常相似。

【讨论】:

我已经测试了您的解决方案,效果很好。非常感谢! 作为脚注,必须记住返回return super(CustomTestRunner, self).setup_databases(*args, **kwargs)。请注意 super 中的*args

以上是关于搭建Django测试环境时如何创建外部数据库?的主要内容,如果未能解决你的问题,请参考以下文章

简单python接口测试编写和django开发环境的搭建

python测试开发django-157.celery异步与redis环境搭建

接口测试框架-Django环境搭建及启动

3.如何搭建Appium自动化测试环境

如何在 Heroku 上运行 Django 测试

CentOS + Python3.6+ Django2.0 + uwsgi + nginx + mysql web发布环境搭建