3

我在 Django 1.8(使用 pytest)上,我有以下配置:

  • Adefaultreadonly由 a 管理的数据库MasterSlaveRouter,根据它们是读取还是写入操作,将 DB 调用定向到一个连接或另一个连接。
  • 在我的开发环境中,settings.DATABASES字典中的两个条目具有相同的设置(它们只是使用不同的连接,但数据库是相同的)。
  • 然而,在我的测试环境中,只有一个default数据库。
  • 每当保存模型时,我post_save都会触发一个信号Foo
  • 我有一个原子操作(用 装饰@transaction.atomic),它修改一个Foo实例并调用.save()它两次。由于没有将自定义using参数传递给装饰器,因此事务仅在default数据库上处于活动状态。

post_save回调创建一个指向的Bar记录,但仅在检查是否存在带有此的记录之后(为了避免)。通过执行以下查询来完成此检查:OneToOneFieldFooBarfoo_idIntegrityError

already_exists = Bar.filter(foo=instance).exists()

这在第一次post_save调用回调时是可以的。创建了一条Bar记录,一切正常。然而,第二次,即使Bar在上一次保存中刚刚创建了这样一个实例Foo,由于过滤是一个读取操作,它是使用readonly连接执行的,因此already_exists最终包含该值False并触发了新记录的创建,最终会抛出一个 IntegrityError ,因为在default连接上执行创建操作时,已经有一条带有 that 的记录foo_id

我尝试将DATABASES字典从 dev_settings 复制到 test_settings,但这破坏了许多测试。然后我阅读了有关override_settings装饰器的信息,并认为它非常适合我的情况。然而,令我惊讶的是,它没有奏效。似乎在某些时候,当应用程序启动时,DATABASES字典(只有default来自 test_settings 的字典)被缓存,然后即使我改变setting.DATABASES了,新值也不再被访问。

如何正确覆盖一项特定测试的数据库配置?

4

1 回答 1

2

嗯...好吧,如果您只使用 pytest,我认为您需要在测试后清理数据库。

现在,要覆盖 django 设置,最好:

from django.test import override_settings
@override_settings(DATABASE_CONFIG=<new_config>)
def test_foo():
    pass

你应该试试 pytest-django:

pytestmark = pytest.mark.django_db

@pytest.mark.django_db
def test_foo():
    pass

当你运行测试时,你可以设置 create-db 参数,强制 py.test 创建一个新的数据库,或者如果你想重用你的数据库,你可以设置reuse-db,比如:

$ py.test --create-db
$ py.test --reuse-db

结帐: 官方文档

于 2016-05-23T16:17:37.067 回答