所以我有各种信号和处理程序,它们通过应用程序发送。但是,当我执行测试/进入“测试模式”时,我希望禁用这些处理程序。
在测试模式下是否有特定于Django的禁用信号/处理程序的方法?我可以想到一个非常简单的方法(在if TESTING子句中包含处理程序)但我想知道Django中是否有更好的方法?...
答案 0 :(得分:76)
我在寻找禁用一组测试用例的信号时发现了这个问题,而且Germano的回答引导我找到解决方案,但它采用相反的方法,所以我想我会添加它。
在您的测试课程中:
class MyTest(TestCase):
def setUp(self):
# do some setup
signal.disconnect(listener, sender=FooModel)
而不是添加决策代码来添加信号,而是在测试点禁用它,这对我来说感觉就像是一个更好的解决方案(因为测试应该围绕代码编写,而不是围绕测试编写代码)。希望对同一条船上的人有用!
编辑:自写这篇文章以来,我已经介绍了另一种禁用信号进行测试的方法。这需要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):
感谢ups:它会在工厂内部和创建对象时静音信号,但是当你想要显式保存()时,不会进一步测试内部 - 信号将在那里取消静音。如果这是一个问题,那么在setUp中使用简单断开连接可能就是这样。
答案 1 :(得分:12)
如果你不想使用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 ...
这应与您的接收器匹配,此示例将匹配此接收器:
@receiver(post_save, sender=MyModel, dispatch_uid="my_id")
我试图在没有指定 dispatch_uid 的情况下禁用信号,但它没有工作。
答案 2 :(得分:6)
不,没有。您可以轻松地建立条件连接:
import sys
if not 'test' in sys.argv:
signal.connect(listener, sender=FooModel)
答案 3 :(得分:3)
您可以执行以下操作
from factory.django import mute_signals
from django.db.models import signals
def test_your_code():
with mute_signals(signals.post_save):
# ... code that doesn't trigger signals
答案 4 :(得分:1)
我有一个类似的问题,无法使用signals.post_save.disconnect()
成功断开信号。发现了this替代方法,该方法创建装饰器以覆盖指定测试和信号上的SUSPEND_SIGNALS
设置。对于同一条船上的任何人都可能有用。
首先,创建装饰器:
import functools
from django.conf import settings
from django.dispatch import receiver
def suspendingreceiver(signal, **decorator_kwargs):
def our_wrapper(func):
@receiver(signal, **decorator_kwargs)
@functools.wraps(func)
def fake_receiver(sender, **kwargs):
if settings.SUSPEND_SIGNALS:
return
return func(sender, **kwargs)
return fake_receiver
return our_wrapper
用新的@receiver
装饰器替换信号:
@suspendingreceiver(post_save, sender=MyModel)
def mymodel_post_save(sender, **kwargs):
work()
在您的TestCase上使用Django的override_settings()
:
@override_settings(SUSPEND_SIGNALS=True)
class MyTestCase(TestCase):
def test_method(self):
Model.objects.create() # post_save_receiver won't execute
感谢撰写博客的Josh Smeaton。
答案 5 :(得分:0)
如果根据文档建议,将接收器连接到AppConfig.ready
中的信号,请参见https://docs.djangoproject.com/en/2.2/topics/signals/#connecting-receiver-functions,则可以使用其他信号接收器创建备用的AppConfig
进行测试。
答案 6 :(得分:0)
最简单的方法是使用灯具。只需将此函数放在将自动运行的任何类之外的测试文件中即可。
from django.db.models.signals import pre_save, post_save
@pytest.fixture(autouse=True) # Automatically use in tests.
def mute_signals(request):
post_save.receivers = []
pre_save.receivers = []
有关更多详细信息,请参见此https://www.cameronmaske.com/muting-django-signals-with-a-pytest-fixture/
答案 7 :(得分:0)
除了我使用@krischan的Factory Boy以外,所有答案都对我不起作用。
对于我来说,我想禁用另一个无法找到reciever
或dispatch_uid
的软件包django_elasticsearch_dsl中的信号。
我不想添加Factory Boy软件包,我设法通过阅读其代码来禁用信号,以了解如何将信号静音,结果非常简单:
from django.db.models import signals
class MyTest(TestCase):
def test_no_signal(self):
signals.post_save.receivers = []
我们可以将post_save
替换为我们要禁用的适当信号,也可以将其放入setUp
方法中进行所有测试。