【问题标题】:How to test signals when using factory_boy with muted signals使用带有静音信号的 factory_boy 时如何测试信号
【发布时间】:2017-07-26 08:06:26
【问题描述】:

我正在使用 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)

当我使用工厂类创建模型实例时,如何测试信号是否有效?

【问题讨论】:

    标签: django factory-boy


    【解决方案1】:

    直接问题的一些解决方案。其次是警告。

    A) mock 不是关闭信号,而是副作用

    @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 是单独的包

    B) Use as context manager 这样您就可以在测试中选择性地禁用

    这将使信号默认开启,但您可以选择性地禁用:

    def test_without_signals(self):
        with factory.django.mute_signals(signals.post_save):
            my_obj = SomeModelTargetFactory()
    
            # ... perform actions w/o signals and assert  ...
    

    C) 静音信号和基础工厂的扩展版本

    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 可以隐藏讨厌的错误

    关于在您自己的代码中使用信号如何产生一种错误的解耦感(例如,post_save本质上与相同覆盖和扩展 save 方法. 我会让你研究一下,看看它是否适用于你的用例。

    绝对会三思而后行将其设为默认值。

    更安全的方法是“静音”/模拟接收者/副作用,而不是发送者

    第三方包经常使用默认的 Django 模型信号。由于包内交互,将这些静音可能会隐藏难以追踪的错误。

    定义和调用(如果需要,然后静音)你自己的信号更好,但通常只是重新发明一个方法调用。 Sentry is a good example of signals being used well in a large codebase.

    解决方案 A 是迄今为止最明确和最安全的。解决方案 B 和 C,不添加您自己的信号需要小心和注意。

    我不会说完全静音post_save 没有用例。这应该是一个例外和一个警告,可能首先要仔细检查需求。

    【讨论】:

    • 非常感谢您的详细描述和用例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-24
    • 1970-01-01
    • 2016-12-10
    • 1970-01-01
    • 2013-07-14
    相关资源
    最近更新 更多