Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock a django signal handler?

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.

like image 798
StefanoP Avatar asked Oct 28 '12 19:10

StefanoP


People also ask

How do you call a signal in Django?

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() .

How do I create a signal in Django?

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.

What is mocking in Django?

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.

How does Django signal work?

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.


1 Answers

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) 
like image 115
Meistro Avatar answered Sep 21 '22 11:09

Meistro