How do I mock a django signal handler?

后端 未结 7 1633
走了就别回头了
走了就别回头了 2020-12-14 00:22

I have a signal_handler connected through a decorator, something like this very simple one:

@receiver(post_save, sender=User, 
          dispatch_uid=\'myfil         


        
7条回答
  •  一个人的身影
    2020-12-14 00:40

    There is a way to mock django signals with a small class.

    You should keep in mind that this would only mock the function as a django signal handler and not the original function; for example, if a m2mchange trigers a call to a function that calls your handler directly, mock.call_count would not be incremented. You would need a separate mock to keep track of those calls.

    Here is the class in question:

    class LocalDjangoSignalsMock():
        def __init__(self, to_mock):
            """ 
            Replaces registered django signals with MagicMocks
    
            :param to_mock: list of signal handlers to mock
            """
            self.mocks = {handler:MagicMock() for handler in to_mock}
            self.reverse_mocks = {magicmock:mocked
                                  for mocked,magicmock in self.mocks.items()}
            django_signals = [signals.post_save, signals.m2m_changed]
            self.registered_receivers = [signal.receivers
                                         for signal in django_signals]
    
        def _apply_mocks(self):
            for receivers in self.registered_receivers:
                for receiver_index in xrange(len(receivers)):
                    handler = receivers[receiver_index]
                    handler_function = handler[1]()
                    if handler_function in self.mocks:
                        receivers[receiver_index] = (
                            handler[0], self.mocks[handler_function])
    
        def _reverse_mocks(self):
            for receivers in self.registered_receivers:
                for receiver_index in xrange(len(receivers)):
                    handler = receivers[receiver_index]
                    handler_function = handler[1]
                    if not isinstance(handler_function, MagicMock):
                        continue
                    receivers[receiver_index] = (
                        handler[0], weakref.ref(self.reverse_mocks[handler_function]))
    
        def __enter__(self):
            self._apply_mocks()
            return self.mocks
    
        def __exit__(self, *args):
            self._reverse_mocks()
    

    Example usage

    to_mock = [my_handler]
    with LocalDjangoSignalsMock(to_mock) as mocks:
        my_trigger()
        for mocked in to_mock:
            assert(mocks[mocked].call_count)
            # 'function {0} was called {1}'.format(
            #      mocked, mocked.call_count)
    

提交回复
热议问题