Ответ 1
Нет, нет. Вы можете легко сделать условное соединение, хотя:
import sys
if not 'test' in sys.argv:
signal.connect(listener, sender=FooModel)
Итак, у меня есть различные сигналы и обработчики, которые отправляются через приложения. Однако, когда я выполняю тесты/перехожу в "режим тестирования", я хочу, чтобы эти обработчики были отключены.
Есть ли способ отключить Django для передачи сигналов/обработчиков в режиме тестирования? Я могу думать о очень простом способе (включая обработчики в предложении if TESTING), но мне было интересно, был ли лучший способ встроен в Django?...
Нет, нет. Вы можете легко сделать условное соединение, хотя:
import sys
if not 'test' in sys.argv:
signal.connect(listener, sender=FooModel)
Я нашел этот вопрос, пытаясь отключить сигнал для набора тестовых примеров, и ответ Germano приведет меня к решению, но он использует противоположный подход, поэтому я решил добавить его.
В вашем тестовом классе:
class MyTest(TestCase):
def setUp(self):
# do some setup
signal.disconnect(listener, sender=FooModel)
Вместо того, чтобы добавлять код принятия решения к добавлению сигнала, я вместо этого отключил его в момент тестирования, который чувствует себя как более приятное решение для меня (так как тесты должны быть написаны вокруг кода, а не кода вокруг тестов). Надеюсь, это полезно для кого-то в одной лодке!
Изменить: с момента написания этого я познакомился с другим способом отключения сигналов для тестирования. Для этого требуется factory_boy package (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: он отключает сигналы внутри factory, и когда объект создается, но не является дальнейшим внутренним тестом, когда вы хотите сделать явный save() - сигнал будет отключен там. Если это проблема, то использование простого отключения в setUp - это, вероятно, путь.
Вот полный пример импорта с тем, как отключить определенный сигнал в тесте, если вы не хотите использовать 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, и это не сработало.
У меня была похожая проблема, и я не смог успешно отключить мой сигнал с помощью signals.post_save.disconnect()
. Нашел этот альтернативный подход, который создает декоратор для переопределения параметра 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
decorator на вашем сигнале новым:
@suspendingreceiver(post_save, sender=MyModel)
def mymodel_post_save(sender, **kwargs):
work()
Используйте Django override_settings()
в вашем TestCase:
@override_settings(SUSPEND_SIGNALS=True)
class MyTestCase(TestCase):
def test_method(self):
Model.objects.create() # post_save_receiver won't execute
Спасибо Джошу Смитону, который написал блог.
Если вы подключаете приемники к сигналам в AppConfig.ready
, что рекомендуется в документации, см. Https://docs.djangoproject.com/en/2.2/topics/signals/#connecting-receiver-functions, вы можете создать альтернативный AppConfig
для ваши тесты с другими приемниками сигнала.