web-dev-qa-db-ja.com

テストする適切な方法Djangoシグナル

送信されたシグナルをテストしようとしていますが、providing_argsです。フォーム送信直後に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')

これは、この信号をテストするための適切な方法ですか?より良いアイデアはありますか?

29
bx2

私は自分で問題を解決しました。最善の解決策は次のとおりだと思います。

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

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.

これで、信号が適切にトリガーされたことをテストしました。

25

mockライブラリを使用する別の提案があります。これは現在Python3の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")

提案の重要な部分は、受信機をモックしてから、信号がその受信機に送信され、一度だけ呼び出されるかどうかをテストすることです。これは、特にカスタムシグナルがある場合、またはシグナルを送信するメソッドを作成していて、ユニットテストでそれらが送信されていることを確認したい場合に最適です。

13
bbengfort

必要がある:

  • 適切な引数およびで信号が発信されたことを表明します。
  • 特定の回数および
  • 適切な順序で。

シグナルのモック を提供する mock_Django アプリを使用できます。

例:

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),
        ])
6
jpic

これの目的は、基礎となるシグナリングメカニズムをテストすることではなく、メソッドが出力するはずの信号が実際に適切な引数で出力されることを確認するための重要な単体テストです。この場合、内部Djangoシグナルであるため、少し些細なことのように見えますが、カスタムシグナルを発行するメソッドを作成した場合を想像してみてください。

5
dana

なぜフレームワークをテストするのですか? Djangoすでにシグナルディスパッチャーの単体テストがあります。フレームワークに問題がないと思われる場合は、単体テストをテストランナーにアタッチしてください。

1
Piotr Czapla