测试Django信号的正确方法

g9icjywg  于 2022-12-20  发布在  Go
关注(0)|答案(7)|浏览(144)

我尝试测试sent signal,它提供了_args. Signal,在表单提交后在contact_question_create视图中触发。
我的测试用例是这样的:

def test_form_should_post_proper_data_via_signal(self):
        form_data = {'name': 'Jan Nowak'}
        signals.question_posted.send(sender='test', form_data=form_data)
        @receiver(signals.question_posted, sender='test')
        def question_posted_listener(sender, form_data):
            self.name = form_data['name']
        eq_(self.name, 'Jan Nowak')

这是测试信号的正确方法吗?有更好的主意吗?

ibps3vxo

ibps3vxo1#

完成您在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.

就这样,你测试了你的信号是否被正确触发。

vmpqdwk3

vmpqdwk32#

我有一个替代建议,使用mock库,它现在是Python 3中unittest.mock标准库的一部分(如果您使用Python 2,则必须使用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")

这个建议的核心部分是模拟一个接收器,然后测试你的信号是否被发送到那个接收器,并且只调用一次。这很好,特别是如果你有自定义信号,或者你已经编写了发送信号的方法,并且你想在单元测试中确保它们被发送。

oipij1gg

oipij1gg3#

我自己解决了这个问题,我认为最好的解决办法是:

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')
jfewjypa

jfewjypa4#

这样做的目的不是测试底层的信号机制,而是一个重要的单元测试,以确保你的方法应该发出的信号实际上是用正确的参数发出的。在这种情况下,它似乎有点微不足道,因为它是一个内部的django信号,但想象一下,如果你写的方法发出一个自定义信号。

kiz8lqtg

kiz8lqtg5#

您需要:

  • Assert用正确的参数发出信号,
  • 特定次数
  • 以适当的顺序。

您可以使用mock_django应用程序,它提供了一个mock for signals
示例:

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),
        ])
e0bqpujr

e0bqpujr6#

为什么你要测试你的框架?Django已经有了信号调度器的单元测试。如果你不相信你的框架是好的,就把它的单元测试附加到你的测试运行器上。

yvfmudvl

yvfmudvl7#

就我而言,我不会测试信号是否发送,我会测试信号处理的预期效果。
在我的用例中,这些信号用于更新Produit.qte属性,比如说,Order.qte_shipped更新了(例如,当我们填写订单时,我希望从该订单的相应产品中减去给定产品的qte)。
因此,我在www.example.com中做了类似这样的事情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

我实际测试的是,当我发货的时候,Produit.qte是正确更新的。我 * 不测试 * 信号工作;这只是可以解释为什么test_order_ship_updates_product()失败的原因之一。
我有点同意“Piotr Czapla”所说的;你在尝试测试这个框架。测试对你代码的影响。

相关问题