Want to disable signals in Django testing

All the answers didn't work for me except when I used Factory Boy by @krischan.

In my case, I want to disable signals that are part of another package django_elasticsearch_dsl which I couldn't locate the reciever or the dispatch_uid.

I don't want to add Factory Boy package, and I managed to disable the signals by reading its code to know how the signals are muted and it turned out very simple:

from django.db.models import signals

class MyTest(TestCase):
    def test_no_signal(self):
        signals.post_save.receivers = []

We can replace post_save with appropriate signal we want to disable, also we can put this in a setUp method for all tests.


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.


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)

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
        signals.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.