Хотите отключить сигналы при тестировании Django

Итак, у меня есть различные сигналы и обработчики, которые отправляются через приложения. Однако, когда я выполняю тесты/перехожу в "режим тестирования", я хочу, чтобы эти обработчики были отключены.

Есть ли способ отключить Django для передачи сигналов/обработчиков в режиме тестирования? Я могу думать о очень простом способе (включая обработчики в предложении if TESTING), но мне было интересно, был ли лучший способ встроен в Django?...

Ответы

Ответ 1

Нет, нет. Вы можете легко сделать условное соединение, хотя:

import sys

if not 'test' in sys.argv:
    signal.connect(listener, sender=FooModel)

Ответ 2

Я нашел этот вопрос, пытаясь отключить сигнал для набора тестовых примеров, и ответ 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 - это, вероятно, путь.

Ответ 3

Вот полный пример импорта с тем, как отключить определенный сигнал в тесте, если вы не хотите использовать 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, и это не сработало.

Ответ 4

У меня была похожая проблема, и я не смог успешно отключить мой сигнал с помощью 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

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

Ответ 5

Если вы подключаете приемники к сигналам в AppConfig.ready, что рекомендуется в документации, см. Https://docs.djangoproject.com/en/2.2/topics/signals/#connecting-receiver-functions, вы можете создать альтернативный AppConfig для ваши тесты с другими приемниками сигнала.