9👍
I’ve resolved the problem by myself. I think that the best solution is following:
def test_form_should_post_proper_data_via_signal(self):
# define the local listener
def question_posted_listener(sender, form_data, **kwargs):
self.name = form_data['name']
# prepare fake data
form_data = {'name': 'Jan Nowak'}
# connect & send the signal
signals.question_posted.connect(question_posted_listener, sender='test')
signals.question_posted.send(sender='test', form_data=form_data)
# check results
eq_(self.name, 'Jan Nowak')
39👍
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.
- [Django]-How can I save my secret keys and password securely in my version control system?
- [Django]-No module named pkg_resources
- [Django]-Django model "doesn't declare an explicit app_label"
23👍
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.
- [Django]-How to change empty_label for modelForm choice field?
- [Django]-Is this the right way to do dependency injection in Django?
- [Django]-How to change status of JsonResponse in Django
8👍
You need to:
- assert a signal was emited with proper arguments and,
- a specific number of times and,
- in appropriate order.
You can use mock_django app which provides a mock for signals.
Example:
from mock import call
def test_install_dependency(self):
with mock_signal_receiver(post_app_install) as install_receiver:
self.env.install(self.music_app)
self.assertEqual(install_receiver.call_args_list, [
call(signal=post_app_install, sender=self.env,
app=self.ukulele_app),
call(signal=post_app_install, sender=self.env,
app=self.music_app),
])
- [Django]-In Django, how does one filter a QuerySet with dynamic field lookups?
- [Django]-How to use UUID
- [Django]-Django REST Framework – Separate permissions per methods
7👍
The purpose of this isn’t to test the underlying signalling mechanism, but rather is an important unit test to ensure that whatever signal your method is supposed to emit is actually emitted with the proper arguments. In this case, it seems a little trivial since its an internal django signal, but imagine if you wrote the method that was emitting a custom signal.
- [Django]-Do django db_index migrations run concurrently?
- [Django]-How to get a particular attribute from queryset in Django in view?
- [Django]-ManyRelatedManager object is not iterable
1👍
Why do you test your framework? Django already have unit tests for signal dispatcher. If you don’t believe that your framework is fine just attach it unit tests to yours test runner.
- [Django]-Http POST drops port in URL
- [Django]-How do you configure Django to send mail through Postfix?
- [Django]-Difference between 'related_name' and 'related_query_name' attributes in Django?
1👍
For my part, I wouldn’t test that the signal is sent. I would test the intended effect of the signals processing.
In my use case, the signals are used to update a Produit.qte attribute when, say, Order.qte_shipped is upated. (E.g. when we fill an order, I want the qte of the given product to be subtracted from the corresponding product for that order).
Thus I do something like this in signals.py:
@receiver(post_save, sender='orders.Order')
@disable_for_loaddata
def quantity_adjust_order(sender, **kwargs):
# retrieve the corresponding product for that order
# subtract Order.qte_shipped from Produit.qte
# save the updated Produit
What I actually test is that Produit.qte is correctly updated when I ship an Order. I do not test that the signals works; that’s just one of the things that COULD explain why test_order_ship_updates_product()
failed.
I somewhat agree with what @Piotr Czapla said; you’re kind of trying to test the framework. Test the effect on your code instead.
- [Django]-Install mysql-python (Windows)
- [Django]-CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False
- [Django]-How to import csv data into django models