Хотите отключить сигналы в тестировании 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

спасибо Джошу Смитону, который написал блог.