【问题标题】:How to override database settings in Django tests?如何覆盖 Django 测试中的数据库设置?
【发布时间】:2016-07-24 00:36:05
【问题描述】:

我使用的是 Django 1.8(使用 pytest),我有以下配置:

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

post_save 回调创建一个Bar 记录,其中OneToOneField 指向Foo,但仅在检查带有此foo_idBar 记录是否已经存在(以避免IntegrityError )。通过执行以下查询来完成此检查:

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

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

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

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

【问题讨论】:

    标签: django transactions pytest pytest-django


    【解决方案1】:

    嗯...如果您只使用 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
    

    结帐: Oficial docs

    【讨论】:

      猜你喜欢
      • 2018-10-20
      • 1970-01-01
      • 2016-03-25
      • 2015-12-29
      • 1970-01-01
      • 2022-10-04
      • 2017-06-12
      • 2018-03-10
      • 1970-01-01
      相关资源
      最近更新 更多