正确测试Django信号的方法

45 投票
7 回答
29312 浏览
提问于 2025-04-16 04:43

我正在尝试测试发送的信号以及它的提供参数。这个信号是在 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')

这样测试这个信号合适吗?有没有更好的方法?

7 个回答

23

我有一个替代的建议,使用的是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")

这个建议的关键部分是模拟一个接收器,然后测试你的信号是否被发送到这个接收器,并且只被调用一次。这非常好,特别是当你有自定义信号,或者你写了发送信号的方法时,你想在单元测试中确保这些信号确实被发送了。

40

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.

通过这个,你就可以测试你的信号是否正确触发了。

10

我自己解决了这个问题。我觉得最好的办法是这样的:

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

撰写回答