想要在Django测试中禁用信号

use*_*502 25 django django-signals django-testing

所以我有各种各样的信号和处理程序,它们通过应用程序发送.但是,当我执行测试/进入"测试模式"时,我希望禁用这些处理程序.

在测试模式下是否有一种特定于Django的禁用信号/处理程序的方法?我可以想到一个非常简单的方法(在if TESTING子句中包含处理程序)但我想知道Django中是否有更好的方法?...

kri*_*han 86

我在寻找禁用一组测试用例的信号时发现了这个问题,而且Germano的回答引导我找到解决方案,但它采用相反的方法,所以我想我会添加它.

在您的测试类中:

class MyTest(TestCase):
    def setUp(self):
        # do some setup
        signal.disconnect(listener, sender=FooModel)
Run Code Online (Sandbox Code Playgroud)

而不是添加决策代码来添加信号,而是在测试时禁用它,这对我来说感觉就像是一个更好的解决方案(因为测试应该围绕代码编写,而不是围绕测试编写代码).希望对同一条船上的人有用!

编辑:自写这篇文章以来,我已经介绍了另一种禁用信号进行测试的方法.这需要factory_boy包(v2.4.0 +),这对于简化Django中的测试非常有用.你真的很喜欢选择:

import factory
from django.db.models import signals

class MyTest(TestCase):
    @factory.django.mute_signals(signals.pre_save, signals.post_save)
    def test_something(self):
Run Code Online (Sandbox Code Playgroud)

警告感谢ups:它会在工厂内部和创建对象时静音信号,但是当你想要显式保存()时,不会进一步测试内部 - 信号将在那里取消静音.如果这是一个问题,那么在setUp中使用简单断开可能是要走的路.

  • @krischan我提醒我不要使用已编辑的解决方案,而是首选.特别是禁用`pre_save`和`post_save`.谁知道其他关键事物正在倾听那些.我认为**静音/模拟接收器(显式)比发送器更好(可以连接到许多隐式静音的接收器)** (3认同)

mrm*_*les 15

如果您不想使用FactoryBoy,这里有一个关于如何在测试中禁用特定信号的导入的完整示例.

from django.db.models import signals
from myapp.models import MyModel

class MyTest(TestCase):

    def test_no_signal(self):
        signals.post_save.disconnect(sender=MyModel, dispatch_uid="my_id")

        ... after this point, the signal is disabled ...
Run Code Online (Sandbox Code Playgroud)

这应与您的接收器匹配,此示例将匹配此接收器:

@receiver(post_save, sender=MyModel, dispatch_uid="my_id")
Run Code Online (Sandbox Code Playgroud)

我试图在没有指定dispatch_uid的情况下禁用信号,但它不起作用.


Ger*_*ano 7

不,那里没有.您可以轻松地建立条件连接:

import sys

if not 'test' in sys.argv:
    signal.connect(listener, sender=FooModel)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,测试始终以`DEBUG = False`([docs](https://docs.djangoproject.com/en/1.4/topics/testing/#other-test-conditions))运行,因此在这种情况下信号将仍然在测试中连接. (3认同)

小智 6

除非我使用@krischan 的Factory Boy,否则所有答案都对我不起作用。

在我的情况下,我想禁用属于另一个包django_elasticsearch_dsl 的信号,我无法找到django_elasticsearch_dslrecieverdispatch_uid.

我不想添加 Factory Boy 包,我设法通过阅读其代码来禁用信号以了解信号是如何静音的,结果非常简单:

from django.db.models import signals

class MyTest(TestCase):
    def test_no_signal(self):
        signals.post_save.receivers = []
Run Code Online (Sandbox Code Playgroud)

我们可以用post_save我们想要禁用的适当信号替换,也可以将其放入setUp所有测试的方法中。