I'm trying to test sent signal and it's providing_args. Signal triggered inside contact_question_create
view just after form submission.
My TestCase is something like:
def test_form_should_post_proper_data_via_signal(self): form_data = {'name': 'Jan Nowak'} signals.question_posted.send(sender='test', form_data=form_data) @receiver(signals.question_posted, sender='test') def question_posted_listener(sender, form_data): self.name = form_data['name'] eq_(self.name, 'Jan Nowak')
Is this the proper way to test this signal? Any better ideas?
The preferred way to write tests in Django is using the unittest module built-in to the Python standard library. This is covered in detail in the Writing and running tests document. You can also use any other Python test framework; Django provides an API and tools for that kind of integration.
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() .
As discussed above, we should test anything that is part of our design or that is defined by code that we have written, but not libraries/code that is already tested by Django or the Python development team. For example, consider the Author model below.
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.
Simplest way to do what you asked in 2015:
from unittest.mock import patch @patch('full.path.to.signals.question_posted.send') def test_question_posted_signal_triggered(self, mock): form = YourForm() form.cleaned_data = {'name': 'Jan Nowak'} form.save() # Check that your signal was called. self.assertTrue(mock.called) # Check that your signal was called only once. self.assertEqual(mock.call_count, 1) # Do whatever else, like actually checking if your signal logic did well.
And with that, you just tested that your signal was properly triggered.
I have an alternative suggestion using the mock
library, which is now part of the unittest.mock
standard library in Python 3 (if you're using Python 2, you'll have to pip install mock
).
try: from unittest.mock import MagicMock except ImportError: from mock import MagicMock def test_form_should_post_proper_data_via_signal(self): """ Assert signal is sent with proper arguments """ # Create handler handler = MagicMock() signals.question_posted.connect(handler, sender='test') # Post the form or do what it takes to send the signal signals.question_posted.send(sender='test', form_data=form_data) # Assert the signal was called only once with the args handler.assert_called_once_with(signal=signals.question_posted, form_data=form_data, sender="test")
The essential part of the suggestion is to mock a receiver, then test whether or not your signal is being sent to that receiver, and called only once. This is great, especially if you have custom signals, or you've written methods that send signals and you want to ensure in your unit tests that they are being sent.
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