I have a signal_handler connected through a decorator, something like this very simple one:
@receiver(post_save, sender=User, dispatch_uid='myfile.signal_handler_post_save_user') def signal_handler_post_save_user(sender, *args, **kwargs): # do stuff
What I want to do is to mock it with the mock library http://www.voidspace.org.uk/python/mock/ in a test, to check how many times django calls it. My code at the moment is something like:
def test_cache(): with mock.patch('myapp.myfile.signal_handler_post_save_user') as mocked_handler: # do stuff that will call the post_save of User self.assert_equal(mocked_handler.call_count, 1)
The problem here is that the original signal handler is called even if mocked, most likely because the @receiver
decorator is storing a copy of the signal handler somewhere, so I'm mocking the wrong code.
So the question: how do I mock my signal handler to make my test work?
Note that if I change my signal handler to:
def _support_function(*args, **kwargs): # do stuff @receiver(post_save, sender=User, dispatch_uid='myfile.signal_handler_post_save_user') def signal_handler_post_save_user(sender, *args, **kwargs): _support_function(*args, **kwargs)
and I mock _support_function
instead, everything works as expected.
There are two ways to send signals in Django. To send a signal, call either Signal. send() (all built-in signals use this) or Signal. send_robust() .
There are 3 types of signal. pre_save/post_save: This signal works before/after the method save(). pre_delete/post_delete: This signal works before after delete a model's instance (method delete()) this signal is thrown.
When mocking in a test, we are in a certain way making fun of our software or of the function we are testing, simulating the behaviour of a specific external functionality. In Python there is a package in the standard library that helps us apply mocks during our tests.
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.
Possibly a better idea is to mock out the functionality inside the signal handler rather than the handler itself. Using the OP's code:
@receiver(post_save, sender=User, dispatch_uid='myfile.signal_handler_post_save_user') def signal_handler_post_save_user(sender, *args, **kwargs): do_stuff() # <-- mock this def do_stuff(): ... do stuff in here
Then mock do_stuff
:
with mock.patch('myapp.myfile.do_stuff') as mocked_handler: self.assert_equal(mocked_handler.call_count, 1)
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