Django:在一个单独的线程中使用相同的测试数据库

时间:2014-04-09 11:10:54

标签: python django psycopg2 pytest

我正在使用具有以下数据库设置的测试数据库运行pytests。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'something',
        'PASSWORD': 'password',

    },
}

使用@ pytest.mark.django_db,我的测试函数访问一个名为' test_postgres'的数据库。为测试而创建。

@pytest.mark.django_db
def test_example():
    from django.db import connection
    cur_ = connection.cursor()
    print cur_.db.settings_dict

输出:

{'ENGINE': 'django.db.backends.postgresql_psycopg2', 'AUTOCOMMIT': True, 'ATOMIC_REQUESTS': False, 'NAME': 'test_postgres', 'TEST_MIRROR': None,...

但如果我在test_example中运行一个线程:

def function_to_run():
    from django.db import connection
    cur_ = connection.cursor
    logger.error(cur_.db.settings_dict)

@pytest.mark.django_db
def test_example():
    p = multiprocessing.Process(target=function_to_run)
    p.start()

我可以看到,在该线程中,光标正在使用名为' postgres'这是非测试数据库。输出:

{'ENGINE': 'django.db.backends.postgresql_psycopg2', 'AUTOCOMMIT': True, 'ATOMIC_REQUESTS': False, 'NAME': 'postgres', 'TEST_MIRROR': None,...

有没有办法将数据库连接参数从原始测试函数传递给我的线程,并告诉我的线程例程使用相同的数据库名称(' test_postgres')作为我的测试函数?

2 个答案:

答案 0 :(得分:2)

我找到了解决问题的方法。

首先,您准备一个单独的Django设置文件进行测试(settings_pytest.py),并使用以下DATABASES设置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'test_database',
        'TEST_NAME': 'test_database',
        'USER': 'something',
        'PASSWORD': 'password',

    },
}

请注意,我们定义了TEST_NAME,它与NAME相同,因此无论是否运行测试运行,我们都将访问相同的数据库。

现在您需要创建此数据库,然后运行' syncdb'并且'迁移'首先:

sql> CREATE DATABASE test_database;

manage.py syncdb --settings=settings_pytest

manage.py migrate --settings=settings_pytest

最后,您可以使用以下命令运行测试:

py.test --reuse-db

您需要指定--reuse-db,因为默认数据库与测试数据库相同,所以数据库重新创建永远不会有效。如果数据库发生更改,则需要使用上述命令手动重新创建数据库。

对于测试本身,如果要向生成的子进程需要访问的数据库添加记录,请记住将事务= True添加到pytest装饰器。

def function_to_run():

    Model.objects.count() == 1

@pytest.mark.django_db(transaction=True)
def test_example():
    obj_ = Model()
    obj_.save()
    p = multiprocessing.Process(target=function_to_run)
    p.start()

答案 1 :(得分:0)

function_to_run()声明中,您正在进行from django.db import connection。您确定将使用正确的测试数据库设置吗?我怀疑你正在使用的装饰器修改connection导入以使用test_postgres而不是postgres但是因为你在装饰器范围之外导入它没有使用正确的导入器。如果你把它放在装饰器包装的函数中会发生什么呢......

@pytest.mark.django_db
def test_example():

    def function_to_run():
        from django.db import connection
        cur_ = connection.cursor
        logger.error(cur_.db.settings_dict)

    p = multiprocessing.Process(target=function_to_run)
    p.start()

编辑:

我对pytest_django并不熟悉所以我此时在黑暗中拍摄,我想象标记功能也允许你装饰一个类,所以你试过把所有想要使用它的测试共享函数和db在一个TestCase类中?像这样:

from django.test import TestCase

@pytest.mark.django_db
class ThreadDBTests(TestCase):

    # The function we want to share among tests
    def function_to_run():
        from django.db import connection
        cur_ = connection.cursor
        logger.error(cur_.db.settings_dict)

    # One of our tests taht needs the db
    def test_example1():
        p = multiprocessing.Process(target=function_to_run)
        p.start()

    # Another test that needs the DB
    def test_example2():
        p = multiprocessing.Process(target=function_to_run)
        p.start()