django - How to test signals when using factory_boy with muted signals -
i using factory_boy package , djangomodelfactory generate factory model muted signals
@factory.django.mute_signals(signals.post_save) class somemodeltargetfactory(djangomodelfactory): name = factory.sequence(lambda x: "name #{}".format(x)) ...
i have post_save signal connected model: def send_notification(sender, instance, created, **kwargs): if created: send_email(...) post_save.connect(send_notification, somemodel)
how can test signals works when create instance of model using factory class?
some solutions direct question. followed caution.
a) instead of turning off signals, mock side effects
@mock.patch('send_email') def test_mocking_signal_side_effects(self, mocked_send_email): my_obj = somemodeltargetfactory() # mocked version of send_email called self.assertequal(mocked_send_email.call_count, 1) my_obj.foo = 'bar' my_obj.save() # didn't call send_email again self.assertequal(mocked_send_email.call_count, 1) note: mock separate package before joining standard lib in 3.3
b) use context manager can selectively disable in tests
this leave signals on default, can selectively disable:
def test_without_signals(self): factory.django.mute_signals(signals.post_save): my_obj = somemodeltargetfactory() # ... perform actions w/o signals , assert ... c) mute signals , extended version of base factory
class somemodeltargetfactory(djangomodelfactory): name = factory.sequence(lambda x: "name #{}".format(x)) # ... @factory.django.mute_signals(signals.post_save) class somemodeltargetfactorynosignals(somemodeltargetfactory): pass i've never tried this, seems should work. additionally, if need objects quick unit test persistence isn't required, maybe factoryboy's build strategy viable option.
caution: muting signals, post_save can hide nasty bugs
there findable references how using signals in own code can create false sense of decoupling (post_save example, essentially same overriding , extending save method. i'll let research see if applies use case.
would think twice making default.
a safer approach "mute"/mock receiver/side effect, not sender.
the default django model signals used third party packages. muting can hide hard track down bugs due intra-package interaction.
defining , calling (and muting if needed) your own signals better, re-inventing method call. sentry example of signals being used in large codebase.
solution far explicit , safe. solution b , c, without addition of own signal requires care , attention.
i wont there no use cases muting post_save entirely. should exception , alert maybe double check need in first place.
Comments
Post a Comment