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?...
Django includes a “signal dispatcher” which helps decoupled applications get notified when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place.
Only use signals to avoid introducing circular dependencies. If you have two apps, and one app wants to trigger behaviour in an app it already knows about, don't use signals. The app should just import the function it needs and call it directly.
Django Signals - post_delete()To notify another part of the application after the delete event of an object happens, you can use the post_delete signal.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With