Ctrlspc Ctrlspc - 5 months ago 52x
Python Question

Testing that I have connected to a particular signal in Django

I have a Django app called "publisher", it connects to various signals in my django project, and when it receives them it sends a message to a rabbitmq queue. What I want to do is to be able to test that my setup code is connecting to the correct signals.

My app structure looks like:

- __init__.py
- signals.py
- tests.py

my __init__.py looks like:

import signals

and my signals.py:

def receiver_function(*args, **kwargs):
#Does rabbitmq stuff


I has thought about patching the receiver function, and checking that the mock was called when I sent the signal:


class SignalsTeste(TestCase):


with patch('publisher.signals.receiver_function') as receiver_mock:
self.assertEquals(receiver_mock.call_count, 1)

However because the signals module is imported, and therefore the signal connections are made before the tests are run, this approach doesn't work as the connections are made before the function is patched......

Can anyone suggest an alternative strategy?


I ran into the same mocking problem you describe. My solution is to reach into Django's signal registry and assert that my function was registered with the correct signal.

Here's my test:

def test_signal_registry(self):
    from foo.models import bar_func  # The function I want to register.
    from django.db.models import signals
    registered_functions = [r[1]() for r in signals.pre_delete.receivers]
    self.assertIn(bar_func, registered_functions)

A little explanation about that list comprehension:

"pre_delete" is the instance of django.dispatch.dispatcher.Signal that I cared about in this case. You would be using your own "my_interesting_signal" in your example. Signals have an internal property called "receivers" that's a list of two-tuples, where the second element is a weakref to the function you register (hence r[1]). Calling a weakref returns the referent.

I had to play around with weakrefs to figure that much out:

import weakref
def foo():
w = weakref.ref(foo)
w() == foo

Hope this helps.