15👍
No, there is not. You can easily make a conditional connection though:
import sys
if not 'test' in sys.argv:
signal.connect(listener, sender=FooModel)
127👍
I found this question when looking to disable a signal for a set of test cases and Germano’s answer lead me to the solution but it takes the opposite approach so I thought I’d add it.
In your test class:
class MyTest(TestCase):
def setUp(self):
# do some setup
signals.disconnect(listener, sender=FooModel)
Instead of adding decision code to adding the signal I instead disabled it at the point of testing which feels like a nicer solution to me (as the tests should be written around the code rather than the code around the tests). Hopefully is useful to someone in the same boat!
Edit: Since writing this I’ve been introduced to another way of disabling signals for testing. This requires the factory_boy package (v2.4.0+) which is very useful for simplifying tests in Django. You’re spoilt for choice really:
import factory
from django.db.models import signals
class MyTest(TestCase):
@factory.django.mute_signals(signals.pre_save, signals.post_save)
def test_something(self):
Caveat thanks to ups: it mutes signals inside factory and when an object is created, but not further inside test when you want to make explicit save() – signal will be unmuted there. If this is an issue then using the simple disconnect in setUp is probably the way to go.
- [Django]-Django Query Related Field Count
- [Django]-Django query annotation with boolean field
- [Django]-Django model constraint for related objects
33👍
Here’s a full example with imports on how to disable a specific signal in a test, if you don’t want to use FactoryBoy.
from django.db.models import signals
from myapp.models import MyModel
class MyTest(TestCase):
def test_no_signal(self):
signals.post_save.disconnect(sender=MyModel, dispatch_uid="my_id")
... after this point, the signal is disabled ...
This should be matched against your receiver, this example would match this receiver:
@receiver(post_save, sender=MyModel, dispatch_uid="my_id")
I tried to disable the signal without specifying the dispatch_uid and it didn’t work.
- [Django]-Django.db.migrations.exceptions.InconsistentMigrationHistory
- [Django]-Programmatically create a django group with permissions
- [Django]-Cancel an already executing task with Celery?
11👍
All the answers didn’t work for me except when I used Factory Boy by @krischan.
In my case, I want to disable signals that are part of another package django_elasticsearch_dsl which I couldn’t locate the reciever
or the dispatch_uid
.
I don’t want to add Factory Boy package, and I managed to disable the signals by reading its code to know how the signals are muted and it turned out very simple:
from django.db.models import signals
class MyTest(TestCase):
def test_no_signal(self):
signals.post_save.receivers = []
We can replace post_save
with appropriate signal we want to disable, also we can put this in a setUp
method for all tests.
- [Django]-What is the SQL ''LIKE" equivalent on Django ORM queries?
- [Django]-Rendering JSON objects using a Django template after an Ajax call
- [Django]-"CSRF token missing or incorrect" while post parameter via AJAX in Django
4👍
I had a similar issue and wasn’t able to successfully disconnect my signal using signals.post_save.disconnect()
. Found this alternative approach that creates a decorator to override the SUSPEND_SIGNALS
setting on specified tests and signals. Might be useful for anyone in the same boat.
First, create the decorator:
import functools
from django.conf import settings
from django.dispatch import receiver
def suspendingreceiver(signal, **decorator_kwargs):
def our_wrapper(func):
@receiver(signal, **decorator_kwargs)
@functools.wraps(func)
def fake_receiver(sender, **kwargs):
if settings.SUSPEND_SIGNALS:
return
return func(sender, **kwargs)
return fake_receiver
return our_wrapper
Replace the usual @receiver
decorator on your signal with the new one:
@suspendingreceiver(post_save, sender=MyModel)
def mymodel_post_save(sender, **kwargs):
work()
Use Django’s override_settings()
on your TestCase:
@override_settings(SUSPEND_SIGNALS=True)
class MyTestCase(TestCase):
def test_method(self):
Model.objects.create() # post_save_receiver won't execute
Thanks to Josh Smeaton, who wrote the blog.
- [Django]-Add custom form fields that are not part of the model (Django)
- [Django]-Run Django shell in IPython
- [Django]-Django 1.7 upgrade error: AppRegistryNotReady: Apps aren't loaded yet
4👍
If you connect receivers to signals in AppConfig.ready
, which is recommended by documentation, see https://docs.djangoproject.com/en/2.2/topics/signals/#connecting-receiver-functions, you can create an alternative AppConfig
for your tests with other signal receivers.
- [Django]-Test that user was logged in successfully
- [Django]-Django column "name" of relation "django_content_type" does not exist
- [Django]-MySQL "incorrect string value" error when save unicode string in Django
4👍
You can do the following
from factory.django import mute_signals
from django.db.models import signals
def test_your_code():
with mute_signals(signals.post_save):
# ... code that doesn't trigger signals
- [Django]-Model not showing up in django admin
- [Django]-How to go from django image field to PIL image and back?
- [Django]-Why is assertDictEqual needed if dicts can be compared by `==`?
4👍
The easiest way is using a fixture. just place this function inside your test file outside any class this will run automatically.
from django.db.models.signals import pre_save, post_save
@pytest.fixture(autouse=True) # Automatically use in tests.
def mute_signals(request):
post_save.receivers = []
pre_save.receivers = []
for more details see this https://www.cameronmaske.com/muting-django-signals-with-a-pytest-fixture/
- [Django]-How can I temporarily disable a foreign key constraint in MySQL?
- [Django]-Force django-admin startproject if project folder already exists
- [Django]-Making django server accessible in LAN
0👍
Factory library has a function that you can use as fixture on functions.
Here is an example on how to implement it.
from django.db.models import signals
from factory.django import mute_signals
from app.models import Model
@mute_signals(signals.pre_save, signals.post_save)
def function():
instance = Model.objects.get(id=1)
instance.attribute = "modify"
instance.save()
- [Django]-Is not JSON serializable
- [Django]-How to update an existing Conda environment with a .yml file
- [Django]-How can I iterate over ManyToManyField?