Want to disable signals in Django testing

戏子无情 提交于 2020-05-09 19:02:07

问题


So I have various signals and handlers which are sent across apps. However, when I perform tests / go into 'testing mode', I want these handlers to be disabled.

Is there a Django-specific way of disabling signals/handlers when in testing mode? I can think of a very simple way (of including the handlers within an if TESTING clause) but I was wondering if there was a better way built into Django?...


回答1:


No, there is not. You can easily make a conditional connection though:

import sys

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



回答2:


I found this question when looking to disable a signal for a set of test cases and Germano's answer lead me to the solution but it takes the opposite approach so I thought I'd add it.

In your test class:

class MyTest(TestCase):
    def setUp(self):
        # do some setup
        signal.disconnect(listener, sender=FooModel)

Instead of adding decision code to adding the signal I instead disabled it at the point of testing which feels like a nicer solution to me (as the tests should be written around the code rather than the code around the tests). Hopefully is useful to someone in the same boat!

Edit: Since writing this I've been introduced to another way of disabling signals for testing. This requires the factory_boy package (v2.4.0+) which is very useful for simplifying tests in Django. You're spoilt for choice really:

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):

Caveat thanks to ups: it mutes signals inside factory and when an object is created, but not further inside test when you want to make explicit save() - signal will be unmuted there. If this is an issue then using the simple disconnect in setUp is probably the way to go.




回答3:


Here's a full example with imports on how to disable a specific signal in a test, if you don't want to use 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 ...

This should be matched against your receiver, this example would match this receiver:

@receiver(post_save, sender=MyModel, dispatch_uid="my_id")

I tried to disable the signal without specifying the dispatch_uid and it didn't work.




回答4:


I had a similar issue and wasn't able to successfully disconnect my signal using signals.post_save.disconnect(). Found this alternative approach that creates a decorator to override the SUSPEND_SIGNALS setting on specified tests and signals. Might be useful for anyone in the same boat.

First, create the decorator:

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

Replace the usual @receiver decorator on your signal with the new one:

@suspendingreceiver(post_save, sender=MyModel)
def mymodel_post_save(sender, **kwargs):
    work()

Use Django's override_settings() on your TestCase:

@override_settings(SUSPEND_SIGNALS=True)
class MyTestCase(TestCase):
    def test_method(self):
        Model.objects.create()  # post_save_receiver won't execute

Thanks to Josh Smeaton, who wrote the blog.




回答5:


If you connect receivers to signals in AppConfig.ready, which is recommended by documentation, see https://docs.djangoproject.com/en/2.2/topics/signals/#connecting-receiver-functions, you can create an alternative AppConfig for your tests with other signal receivers.



来源:https://stackoverflow.com/questions/18532539/want-to-disable-signals-in-django-testing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!