Хотите отключить сигналы в тестировании Django
поэтому у меня есть различные сигналы и обработчики, которые отправляются через приложения. Однако, когда я выполняю тесты / перехожу в "режим тестирования", я хочу, чтобы эти обработчики были отключены.
есть ли специфичный для Django способ отключения сигналов / обработчиков в режиме тестирования? Я могу придумать очень простой способ (включить обработчики в предложение if TESTING), но мне было интересно, есть ли лучший способ, встроенный в Django?...
4 ответов
нет, нет. Вы можете легко сделать условное соединение:
import sys
if not 'test' in sys.argv:
signal.connect(listener, sender=FooModel)
Я нашел этот вопрос, когда искал отключить сигнал для набора тестовых случаев, и ответ Джермано привел меня к решению, но он принимает противоположный подход, поэтому я подумал, что добавлю его.
в вашем тестовом классе:
class MyTest(TestCase):
def setUp(self):
# do some setup
signal.disconnect(listener, sender=FooModel)
вместо добавления кода решения к добавлению сигнала я вместо этого отключил его в момент тестирования, который кажется мне более приятным решением (поскольку тесты должны быть написаны вокруг кода, а не кода вокруг тестов). Надеюсь, это полезно для кого-то в той же лодке!
Edit: с момента написания этого я познакомился с другим способом отключения сигналов для тестирования. Для этого требуется 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: он отключает сигналы внутри фабрики и при создании объекта, но не далее внутри теста, когда вы хотите сделать явное сохранение () - сигнал будет происходит там. Если это проблема, то использование простого отключения в настройке, вероятно,путь.
вот полный пример с импортом о том, как отключить определенный сигнал в тесте, если вы не хотите использовать 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
декоратора по вашему сигналу с новым:
@suspendingreceiver(post_save, sender=MyModel)
def mymodel_post_save(sender, **kwargs):
work()
использовать Джанго override_settings()
on свой TestCase:
@override_settings(SUSPEND_SIGNALS=True)
class MyTestCase(TestCase):
def test_method(self):
Model.objects.create() # post_save_receiver won't execute
спасибо Джошу Смитону, который написал блог.