Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Want to disable signals in Django testing

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

like image 870
user2564502 Avatar asked Aug 30 '13 12:08

user2564502


People also ask

What are the signals in 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.

Should I use signals Django?

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.

What is the use of the Post_delete signal in Django?

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.


2 Answers

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.

like image 182
krischan Avatar answered Oct 02 '22 05:10

krischan


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.

like image 36
mrmuggles Avatar answered Oct 02 '22 05:10

mrmuggles