我正在使用factory_boy包和DjangoModelFactory
生成带有静音信号的工厂模型
@factory.django.mute_signals(signals.post_save)
class SomeModelTargetFactory(DjangoModelFactory):
name = factory.Sequence(lambda x: "Name #{}".format(x))
...
我有一个post_save
信号连接到模型:
def send_notification(sender, instance, created, **kwargs):
if created:
send_email(...)
post_save.connect(send_notification, SomeModel)
当我使用工厂类创建模型实例时,如何测试信号是否有效?
答案 0 :(得分:4)
直接问题的一些解决方案。紧随其后。
@mock.patch('send_email')
def test_mocking_signal_side_effects(self, mocked_send_email):
my_obj = SomeModelTargetFactory()
# mocked version of send_email was 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)
注意:在加入3.3
中的标准库之前,mock是单独的包默认情况下会保持信号开启,但您可以选择性地禁用:
def test_without_signals(self):
with factory.django.mute_signals(signals.post_save):
my_obj = SomeModelTargetFactory()
# ... perform actions w/o signals and assert ...
class SomeModelTargetFactory(DjangoModelFactory):
name = factory.Sequence(lambda x: "Name #{}".format(x))
# ...
@factory.django.mute_signals(signals.post_save)
class SomeModelTargetFactoryNoSignals(SomeModelTargetFactory):
pass
我从来没有尝试过这个,但它似乎应该有效。此外,如果您只需要快速单元测试的对象,而不需要持久性,那么FactoryBoy's BUILD strategy可能是一个可行的选择。
很容易找到关于如何在自己的代码中使用信号会产生错误的解耦感的参考文献(post_save
例如,与覆盖和扩展{{基本上相同 1}}方法。我会让你研究一下它是否适用于你的用例。
肯定会三思而后行。
更安全的方法是“静音”/模拟接收器/副作用,而不是发送者。
第三方软件包经常使用默认的Django模型信号。将那些隐藏起来可以隐藏起来,以便跟踪因包内交互而导致的错误。
定义和调用(然后在需要时静音)你自己的信号更好,但通常只是重新发明一个方法调用。 Sentry is a good example of signals being used well in a large codebase.
解决方案A是迄今为止最明确和最安全的解决方案。解决方案B和C,无需添加自己的信号,需要小心谨慎。
我不会说没有完全静音save
的用例。它应该是一个例外,并且可能会首先仔细检查需求。